feat: implement batch operations API for sequential multi-operation execution

- Add BatchOperationManager class with singleton pattern
- Support 7 operation types: save, export, delete_by_path, hierarchy_delete, shrinkwrap, close, open
- Implement sequential execution with individual error isolation
- Add JSON parsing helper for operations array
- Register /api/creo/batch-operations endpoint
- Fix namespace declaration errors in header file

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sladro 2025-10-13 17:42:54 +08:00
parent a02b68c7e3
commit a1e0237c9e
39 changed files with 915 additions and 3 deletions

586
BatchOperationManager.cpp Normal file
View File

@ -0,0 +1,586 @@
#include "pch.h"
#include "BatchOperationManager.h"
#include "CreoManager.h"
#include "PathDeleteManager.h"
#include "ShrinkwrapManager.h"
#include <sstream>
#include <chrono>
#include <iomanip>
// Helper: Get current time as string
std::string BatchOperationManager::GetCurrentTimeString() {
auto now = std::chrono::system_clock::now();
auto now_time = std::chrono::system_clock::to_time_t(now);
std::tm local_time;
localtime_s(&local_time, &now_time);
std::ostringstream oss;
oss << std::put_time(&local_time, "%Y-%m-%d %H:%M:%S");
return oss.str();
}
// Helper: Escape JSON string
std::string BatchOperationManager::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;
}
// Build JSON result for SaveModel
std::string BatchOperationManager::BuildSaveResultJson(const SaveResult& result) {
std::ostringstream json;
json << "{"
<< "\"file_size\":\"" << EscapeJsonString(result.file_size) << "\","
<< "\"save_time\":\"" << EscapeJsonString(result.save_time) << "\","
<< "\"software\":\"" << EscapeJsonString(result.software) << "\","
<< "\"original_file\":\"" << EscapeJsonString(result.original_file) << "\""
<< "}";
return json.str();
}
// Build JSON result for ExportModel
std::string BatchOperationManager::BuildExportResultJson(const ExportResult& result) {
std::ostringstream json;
json << "{"
<< "\"export_path\":\"" << EscapeJsonString(result.export_path) << "\","
<< "\"file_size\":\"" << EscapeJsonString(result.file_size) << "\","
<< "\"format\":\"" << EscapeJsonString(result.format) << "\","
<< "\"export_time\":\"" << EscapeJsonString(result.export_time) << "\","
<< "\"software\":\"" << EscapeJsonString(result.software) << "\","
<< "\"original_file\":\"" << EscapeJsonString(result.original_file) << "\","
<< "\"dirname\":\"" << EscapeJsonString(result.dirname) << "\","
<< "\"filename\":\"" << EscapeJsonString(result.filename) << "\""
<< "}";
return json.str();
}
// Build JSON result for DeleteByPath
std::string BatchOperationManager::BuildDeleteByPathResultJson(const PathDeleteManager::PathDeleteResult& result) {
std::ostringstream json;
json << "{"
<< "\"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 << "],\"total_requested\":" << result.total_requested
<< ",\"successful\":" << result.successful
<< ",\"failed\":" << result.failed
<< "}";
return json.str();
}
// Build JSON result for HierarchyDelete
std::string BatchOperationManager::BuildHierarchyDeleteResultJson(const CreoManager::HierarchyDeleteResult& result) {
std::ostringstream json;
json << "{"
<< "\"message\":\"" << EscapeJsonString(result.message) << "\","
<< "\"original_levels\":" << result.original_levels << ","
<< "\"target_level\":" << result.target_level << ","
<< "\"final_levels\":" << result.final_levels << ","
<< "\"total_deleted\":" << result.total_deleted << ","
<< "\"successful\":" << result.successful << ","
<< "\"failed\":" << result.failed
<< "}";
return json.str();
}
// Build JSON result for Shrinkwrap
std::string BatchOperationManager::BuildShrinkwrapResultJson(const ShrinkwrapShellResult& result) {
std::ostringstream json;
json << "{"
<< "\"message\":\"" << EscapeJsonString(result.message) << "\","
<< "\"output_file_path\":\"" << EscapeJsonString(result.parameters.output_file_path) << "\","
<< "\"output_file_size\":\"" << EscapeJsonString(result.parameters.output_file_size) << "\","
<< "\"shrinkwrap_time\":\"" << EscapeJsonString(result.parameters.shrinkwrap_time) << "\","
<< "\"quality\":" << result.parameters.quality << ","
<< "\"chord_height\":" << result.parameters.chord_height
<< "}";
return json.str();
}
// Build JSON result for CloseModel
std::string BatchOperationManager::BuildCloseResultJson(const CloseResult& result) {
std::ostringstream json;
json << "{"
<< "\"model_name\":\"" << EscapeJsonString(result.model_name) << "\","
<< "\"was_modified\":" << (result.was_modified ? "true" : "false") << ","
<< "\"close_time\":\"" << EscapeJsonString(result.close_time) << "\""
<< "}";
return json.str();
}
// Build JSON result for OpenModel
std::string BatchOperationManager::BuildOpenResultJson(const OpenResult& result) {
std::ostringstream json;
json << "{"
<< "\"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
<< "}";
return json.str();
}
// Execute save_model operation
BatchOperationResult BatchOperationManager::ExecuteSaveModel(int index, const BatchOperation& operation) {
BatchOperationResult result;
result.operation_index = index;
result.operation_type = "save_model";
auto start = std::chrono::high_resolution_clock::now();
try {
SaveResult save_result = CreoManager::Instance().SaveModel();
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
result.execution_time = std::to_string(duration.count()) + "ms";
result.success = save_result.success;
if (save_result.success) {
result.result_json = BuildSaveResultJson(save_result);
} else {
result.error_message = save_result.error_message;
}
} catch (const std::exception& e) {
result.success = false;
result.error_message = "Exception: " + std::string(e.what());
} catch (...) {
result.success = false;
result.error_message = "Unknown error during save operation";
}
return result;
}
// Execute export_model operation
BatchOperationResult BatchOperationManager::ExecuteExportModel(int index, const BatchOperation& operation) {
BatchOperationResult result;
result.operation_index = index;
result.operation_type = "export_model";
auto start = std::chrono::high_resolution_clock::now();
try {
// Extract parameters
std::string export_path;
std::string geom_flags = "solids";
auto it = operation.parameters.find("export_path");
if (it != operation.parameters.end()) {
export_path = it->second;
}
it = operation.parameters.find("geom_flags");
if (it != operation.parameters.end()) {
geom_flags = it->second;
}
if (export_path.empty()) {
result.success = false;
result.error_message = "Missing required parameter: export_path";
return result;
}
ExportResult export_result = CreoManager::Instance().ExportModelToSTEP(export_path, geom_flags);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
result.execution_time = std::to_string(duration.count()) + "ms";
result.success = export_result.success;
if (export_result.success) {
result.result_json = BuildExportResultJson(export_result);
} else {
result.error_message = export_result.error_message;
}
} catch (const std::exception& e) {
result.success = false;
result.error_message = "Exception: " + std::string(e.what());
} catch (...) {
result.success = false;
result.error_message = "Unknown error during export operation";
}
return result;
}
// Execute delete_by_path operation
BatchOperationResult BatchOperationManager::ExecuteDeleteByPath(int index, const BatchOperation& operation) {
BatchOperationResult result;
result.operation_index = index;
result.operation_type = "delete_by_path";
auto start = std::chrono::high_resolution_clock::now();
try {
PathDeleteManager::PathDeleteRequest delete_request;
delete_request.software_type = "creo";
delete_request.component_paths = operation.array_parameters;
auto it = operation.parameters.find("force_delete");
if (it != operation.parameters.end()) {
delete_request.force_delete = (it->second == "true");
}
if (delete_request.component_paths.empty()) {
result.success = false;
result.error_message = "Missing required parameter: component_paths";
return result;
}
PathDeleteManager::PathDeleteResult delete_result =
PathDeleteManager::Instance().DeleteComponentsByPaths(delete_request);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
result.execution_time = std::to_string(duration.count()) + "ms";
result.success = delete_result.success;
if (delete_result.success) {
result.result_json = BuildDeleteByPathResultJson(delete_result);
} else {
result.error_message = delete_result.error_message;
}
} catch (const std::exception& e) {
result.success = false;
result.error_message = "Exception: " + std::string(e.what());
} catch (...) {
result.success = false;
result.error_message = "Unknown error during delete by path operation";
}
return result;
}
// Execute hierarchy_delete operation
BatchOperationResult BatchOperationManager::ExecuteHierarchyDelete(int index, const BatchOperation& operation) {
BatchOperationResult result;
result.operation_index = index;
result.operation_type = "hierarchy_delete";
auto start = std::chrono::high_resolution_clock::now();
try {
std::string project_name;
int target_level = 0;
auto it = operation.parameters.find("project_name");
if (it != operation.parameters.end()) {
project_name = it->second;
}
it = operation.parameters.find("target_level");
if (it != operation.parameters.end()) {
try {
target_level = std::stoi(it->second);
} catch (...) {
result.success = false;
result.error_message = "Invalid target_level parameter";
return result;
}
}
if (project_name.empty()) {
result.success = false;
result.error_message = "Missing required parameter: project_name";
return result;
}
CreoManager::HierarchyDeleteResult delete_result =
CreoManager::Instance().DeleteHierarchyComponents(project_name, target_level);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
result.execution_time = std::to_string(duration.count()) + "ms";
result.success = delete_result.success;
if (delete_result.success) {
result.result_json = BuildHierarchyDeleteResultJson(delete_result);
} else {
result.error_message = delete_result.error_message;
}
} catch (const std::exception& e) {
result.success = false;
result.error_message = "Exception: " + std::string(e.what());
} catch (...) {
result.success = false;
result.error_message = "Unknown error during hierarchy delete operation";
}
return result;
}
// Execute shrinkwrap_shell operation
BatchOperationResult BatchOperationManager::ExecuteShrinkwrapShell(int index, const BatchOperation& operation) {
BatchOperationResult result;
result.operation_index = index;
result.operation_type = "shrinkwrap_shell";
auto start = std::chrono::high_resolution_clock::now();
try {
ShrinkwrapShellRequest shrink_request;
// Extract parameters
auto it = operation.parameters.find("output_file_path");
if (it != operation.parameters.end()) {
shrink_request.output_file_path = it->second;
}
it = operation.parameters.find("quality");
if (it != operation.parameters.end()) {
try {
shrink_request.quality = std::stoi(it->second);
} catch (...) {}
}
it = operation.parameters.find("chord_height");
if (it != operation.parameters.end()) {
try {
shrink_request.chord_height = std::stod(it->second);
} catch (...) {}
}
if (shrink_request.output_file_path.empty()) {
result.success = false;
result.error_message = "Missing required parameter: output_file_path";
return result;
}
ShrinkwrapShellResult shrink_result =
ShrinkwrapManager::Instance().ExecuteShrinkwrapShell(shrink_request);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
result.execution_time = std::to_string(duration.count()) + "ms";
result.success = shrink_result.success;
if (shrink_result.success) {
result.result_json = BuildShrinkwrapResultJson(shrink_result);
} else {
result.error_message = shrink_result.error_message;
}
} catch (const std::exception& e) {
result.success = false;
result.error_message = "Exception: " + std::string(e.what());
} catch (...) {
result.success = false;
result.error_message = "Unknown error during shrinkwrap operation";
}
return result;
}
// Execute close_model operation
BatchOperationResult BatchOperationManager::ExecuteCloseModel(int index, const BatchOperation& operation) {
BatchOperationResult result;
result.operation_index = index;
result.operation_type = "close_model";
auto start = std::chrono::high_resolution_clock::now();
try {
bool force_close = false;
auto it = operation.parameters.find("force_close");
if (it != operation.parameters.end()) {
force_close = (it->second == "true");
}
CloseResult close_result = CreoManager::Instance().CloseModel(force_close);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
result.execution_time = std::to_string(duration.count()) + "ms";
result.success = close_result.success;
if (close_result.success) {
result.result_json = BuildCloseResultJson(close_result);
} else {
result.error_message = close_result.error_message;
}
} catch (const std::exception& e) {
result.success = false;
result.error_message = "Exception: " + std::string(e.what());
} catch (...) {
result.success = false;
result.error_message = "Unknown error during close operation";
}
return result;
}
// Execute open_model operation
BatchOperationResult BatchOperationManager::ExecuteOpenModel(int index, const BatchOperation& operation) {
BatchOperationResult result;
result.operation_index = index;
result.operation_type = "open_model";
auto start = std::chrono::high_resolution_clock::now();
try {
std::string file_path;
std::string open_mode = "active";
auto it = operation.parameters.find("file_path");
if (it != operation.parameters.end()) {
file_path = it->second;
}
it = operation.parameters.find("open_mode");
if (it != operation.parameters.end()) {
open_mode = it->second;
}
if (file_path.empty()) {
result.success = false;
result.error_message = "Missing required parameter: file_path";
return result;
}
OpenResult open_result = CreoManager::Instance().OpenModel(file_path, open_mode);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
result.execution_time = std::to_string(duration.count()) + "ms";
result.success = open_result.success;
if (open_result.success) {
result.result_json = BuildOpenResultJson(open_result);
} else {
result.error_message = open_result.error_message;
}
} catch (const std::exception& e) {
result.success = false;
result.error_message = "Exception: " + std::string(e.what());
} catch (...) {
result.success = false;
result.error_message = "Unknown error during open operation";
}
return result;
}
// Main entry point: Execute batch operations
BatchOperationsResponse BatchOperationManager::ExecuteBatchOperations(const BatchOperationsRequest& request) {
BatchOperationsResponse response;
response.total_operations = static_cast<int>(request.operations.size());
auto start = std::chrono::high_resolution_clock::now();
try {
// Validate request
if (request.software_type != "creo") {
response.success = false;
response.error_message = "Invalid software_type, must be 'creo'";
return response;
}
if (request.operations.empty()) {
response.success = false;
response.error_message = "No operations specified";
return response;
}
// Execute each operation sequentially
for (size_t i = 0; i < request.operations.size(); i++) {
const BatchOperation& operation = request.operations[i];
BatchOperationResult op_result;
if (operation.operation_type == "save_model") {
op_result = ExecuteSaveModel(static_cast<int>(i), operation);
} else if (operation.operation_type == "export_model") {
op_result = ExecuteExportModel(static_cast<int>(i), operation);
} else if (operation.operation_type == "delete_by_path") {
op_result = ExecuteDeleteByPath(static_cast<int>(i), operation);
} else if (operation.operation_type == "hierarchy_delete") {
op_result = ExecuteHierarchyDelete(static_cast<int>(i), operation);
} else if (operation.operation_type == "shrinkwrap_shell") {
op_result = ExecuteShrinkwrapShell(static_cast<int>(i), operation);
} else if (operation.operation_type == "close_model") {
op_result = ExecuteCloseModel(static_cast<int>(i), operation);
} else if (operation.operation_type == "open_model") {
op_result = ExecuteOpenModel(static_cast<int>(i), operation);
} else {
// Unknown operation type
op_result.operation_index = static_cast<int>(i);
op_result.operation_type = operation.operation_type;
op_result.success = false;
op_result.error_message = "Unknown operation type: " + operation.operation_type;
}
response.results.push_back(op_result);
if (op_result.success) {
response.successful_operations++;
} else {
response.failed_operations++;
}
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
response.execution_time = std::to_string(duration.count()) + "ms";
// Overall success if at least one operation succeeded
response.success = (response.successful_operations > 0);
if (response.success) {
response.message = "Batch operations completed";
} else {
response.message = "All batch operations failed";
response.error_message = "All operations failed to execute";
}
} catch (const std::exception& e) {
response.success = false;
response.error_message = "Exception during batch operations: " + std::string(e.what());
} catch (...) {
response.success = false;
response.error_message = "Unknown error during batch operations";
}
return response;
}

82
BatchOperationManager.h Normal file
View File

@ -0,0 +1,82 @@
#pragma once
#include <string>
#include <vector>
#include <map>
#include "CreoManager.h"
#include "PathDeleteManager.h"
#include "ShrinkwrapManager.h"
// Single operation request structure
struct BatchOperation {
std::string operation_type; // "save_model", "export_model", "delete_by_path", etc.
std::map<std::string, std::string> parameters; // Operation-specific parameters
std::vector<std::string> array_parameters; // For array parameters like component_paths
};
// Single operation result structure
struct BatchOperationResult {
int operation_index = 0;
std::string operation_type;
bool success = false;
std::string result_json; // JSON string of operation result
std::string error_message;
std::string execution_time;
};
// Batch operations request structure
struct BatchOperationsRequest {
std::string software_type = "creo";
std::vector<BatchOperation> operations;
};
// Batch operations overall result structure
struct BatchOperationsResponse {
bool success = false;
std::string message;
int total_operations = 0;
int successful_operations = 0;
int failed_operations = 0;
std::string execution_time;
std::vector<BatchOperationResult> results;
std::string error_message;
};
// Batch Operation Manager Class
class BatchOperationManager {
public:
// Get singleton instance
static BatchOperationManager& Instance() {
static BatchOperationManager instance;
return instance;
}
// Main entry point: execute batch operations
BatchOperationsResponse ExecuteBatchOperations(const BatchOperationsRequest& request);
private:
// Private constructor for singleton
BatchOperationManager() = default;
BatchOperationManager(const BatchOperationManager&) = delete;
BatchOperationManager& operator=(const BatchOperationManager&) = delete;
// Execute individual operations
BatchOperationResult ExecuteSaveModel(int index, const BatchOperation& operation);
BatchOperationResult ExecuteExportModel(int index, const BatchOperation& operation);
BatchOperationResult ExecuteDeleteByPath(int index, const BatchOperation& operation);
BatchOperationResult ExecuteHierarchyDelete(int index, const BatchOperation& operation);
BatchOperationResult ExecuteShrinkwrapShell(int index, const BatchOperation& operation);
BatchOperationResult ExecuteCloseModel(int index, const BatchOperation& operation);
BatchOperationResult ExecuteOpenModel(int index, const BatchOperation& operation);
// Helper functions
std::string GetCurrentTimeString();
std::string EscapeJsonString(const std::string& str);
std::string BuildSaveResultJson(const SaveResult& result);
std::string BuildExportResultJson(const ExportResult& result);
std::string BuildDeleteByPathResultJson(const PathDeleteManager::PathDeleteResult& result);
std::string BuildHierarchyDeleteResultJson(const CreoManager::HierarchyDeleteResult& result);
std::string BuildShrinkwrapResultJson(const ShrinkwrapShellResult& result);
std::string BuildCloseResultJson(const CloseResult& result);
std::string BuildOpenResultJson(const OpenResult& result);
};

View File

@ -12,6 +12,7 @@
#include "ModelSearchHandler.h"
#include "HierarchyStatisticsAnalyzer.h"
#include "ComponentChildrenManager.h"
#include "BatchOperationManager.h"
#include <wfcSession.h>
#include <wfcGlobal.h>
#include <string>
@ -1751,6 +1752,237 @@ HttpResponse ComponentChildrenHandler(const HttpRequest& request) {
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"};
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;
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);
// 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,
@ -1788,8 +2020,9 @@ extern "C" int user_initialize(
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 {

View File

@ -207,6 +207,7 @@ ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AuthManager.cpp" />
<ClCompile Include="BatchOperationManager.cpp" />
<ClCompile Include="ComponentChildrenManager.cpp" />
<ClCompile Include="CreoManager.cpp" />
<ClCompile Include="CreoUtilities.cpp" />
@ -238,6 +239,7 @@ ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AuthManager.h" />
<ClInclude Include="BatchOperationManager.h" />
<ClInclude Include="ComponentChildrenManager.h" />
<ClInclude Include="Config.h" />
<ClInclude Include="CreoManager.h" />

View File

@ -96,6 +96,9 @@
<ClCompile Include="CreoUtilities.cpp">
<Filter>源文件\src\utils</Filter>
</ClCompile>
<ClCompile Include="BatchOperationManager.cpp">
<Filter>源文件\src\creo</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="MFCCreoDll.def">
@ -184,6 +187,9 @@
<ClInclude Include="CreoUtilities.h">
<Filter>源文件\src\utils</Filter>
</ClInclude>
<ClInclude Include="BatchOperationManager.h">
<Filter>源文件\src\creo</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="MFCCreoDll.rc">

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,8 @@
C:\Users\sladr\source\repos\MFCCreoDll\AuthManager.cpp;C:\Users\sladr\source\repos\MFCCreoDll\MFCCreoDll\x64\Debug\AuthManager.obj
C:\Users\sladr\source\repos\MFCCreoDll\BatchOperationManager.cpp;C:\Users\sladr\source\repos\MFCCreoDll\MFCCreoDll\x64\Debug\BatchOperationManager.obj
C:\Users\sladr\source\repos\MFCCreoDll\ComponentChildrenManager.cpp;C:\Users\sladr\source\repos\MFCCreoDll\MFCCreoDll\x64\Debug\ComponentChildrenManager.obj
C:\Users\sladr\source\repos\MFCCreoDll\CreoManager.cpp;C:\Users\sladr\source\repos\MFCCreoDll\MFCCreoDll\x64\Debug\CreoManager.obj
C:\Users\sladr\source\repos\MFCCreoDll\CreoUtilities.cpp;C:\Users\sladr\source\repos\MFCCreoDll\MFCCreoDll\x64\Debug\CreoUtilities.obj
C:\Users\sladr\source\repos\MFCCreoDll\GeometryAnalyzer.cpp;C:\Users\sladr\source\repos\MFCCreoDll\MFCCreoDll\x64\Debug\GeometryAnalyzer.obj
C:\Users\sladr\source\repos\MFCCreoDll\HierarchyStatisticsAnalyzer.cpp;C:\Users\sladr\source\repos\MFCCreoDll\MFCCreoDll\x64\Debug\HierarchyStatisticsAnalyzer.obj
C:\Users\sladr\source\repos\MFCCreoDll\HttpRouter.cpp;C:\Users\sladr\source\repos\MFCCreoDll\MFCCreoDll\x64\Debug\HttpRouter.obj

View File

@ -1,3 +1,3 @@
^C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\AUTHMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\CREOMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\GEOMETRYANALYZER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\HIERARCHYSTATISTICSANALYZER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\HTTPROUTER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\HTTPSERVER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\JSONHELPER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\LOGGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MFCCREODLL.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MFCCREODLL.RES|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MODELANALYZER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MODELSEARCHENGINE.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MODELSEARCHHANDLER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\PATHDELETEMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\PCH.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\SERVERMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\SHELLEXPORTHANDLER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\SHRINKWRAPMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\WEBSOCKETSERVER.OBJ
^C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\AUTHMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\BATCHOPERATIONMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\COMPONENTCHILDRENMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\CREOMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\CREOUTILITIES.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\GEOMETRYANALYZER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\HIERARCHYSTATISTICSANALYZER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\HTTPROUTER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\HTTPSERVER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\JSONHELPER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\LOGGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MFCCREODLL.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MFCCREODLL.RES|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MODELANALYZER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MODELSEARCHENGINE.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\MODELSEARCHHANDLER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\PATHDELETEMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\PCH.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\SERVERMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\SHELLEXPORTHANDLER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\SHRINKWRAPMANAGER.OBJ|C:\USERS\SLADR\SOURCE\REPOS\MFCCREODLL\MFCCREODLL\X64\DEBUG\WEBSOCKETSERVER.OBJ
C:\Users\sladr\source\repos\MFCCreoDll\x64\Debug\MFCCreoDll.lib
C:\Users\sladr\source\repos\MFCCreoDll\x64\Debug\MFCCreoDll.EXP

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.