更新配置文件,添加批处理回调服务器地址和令牌的默认值;优化批处理操作处理逻辑
This commit is contained in:
parent
a3b2765419
commit
f6d867dae4
6
Config.h
6
Config.h
@ -7,8 +7,10 @@ public:
|
|||||||
static const int HTTP_PORT = 12345;
|
static const int HTTP_PORT = 12345;
|
||||||
static const int WEBSOCKET_PORT = 12346;
|
static const int WEBSOCKET_PORT = 12346;
|
||||||
|
|
||||||
// API配置
|
// API配置
|
||||||
static constexpr const char* API_PREFIX = "/api";
|
static constexpr const char* API_PREFIX = "/api";
|
||||||
|
static constexpr const char* BATCH_CALLBACK_SERVER_ADDRESS = "";
|
||||||
|
static constexpr const char* BATCH_CALLBACK_TOKEN = "";
|
||||||
|
|
||||||
// 超时配置
|
// 超时配置
|
||||||
static const int HTTP_TIMEOUT_MS = 30000; // 30秒
|
static const int HTTP_TIMEOUT_MS = 30000; // 30秒
|
||||||
|
|||||||
325
MFCCreoDll.cpp
325
MFCCreoDll.cpp
@ -12,14 +12,23 @@
|
|||||||
#include "ModelSearchHandler.h"
|
#include "ModelSearchHandler.h"
|
||||||
#include "HierarchyStatisticsAnalyzer.h"
|
#include "HierarchyStatisticsAnalyzer.h"
|
||||||
#include "ComponentChildrenManager.h"
|
#include "ComponentChildrenManager.h"
|
||||||
#include "BatchOperationManager.h"
|
#include "BatchOperationManager.h"
|
||||||
#include <wfcSession.h>
|
#include "Config.h"
|
||||||
#include <wfcGlobal.h>
|
#include <wfcSession.h>
|
||||||
#include <string>
|
#include <wfcGlobal.h>
|
||||||
#include <sstream>
|
#include <Windows.h>
|
||||||
#include <regex>
|
#include <winhttp.h>
|
||||||
#include <atomic>
|
#include <string>
|
||||||
#include <memory>
|
#include <sstream>
|
||||||
|
#include <regex>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#pragma comment(lib, "winhttp.lib")
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define new DEBUG_NEW
|
#define new DEBUG_NEW
|
||||||
@ -351,7 +360,7 @@ bool ExtractJsonBool(const std::string& json, const std::string& key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// JSON字符串转义函数
|
// JSON字符串转义函数
|
||||||
std::string EscapeJsonString(const std::string& str) {
|
std::string EscapeJsonString(const std::string& str) {
|
||||||
std::string escaped = str;
|
std::string escaped = str;
|
||||||
|
|
||||||
// Replace backslashes
|
// Replace backslashes
|
||||||
@ -382,8 +391,258 @@ std::string EscapeJsonString(const std::string& str) {
|
|||||||
pos += 2;
|
pos += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return escaped;
|
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) {
|
HttpResponse ExportModelHandler(const HttpRequest& request) {
|
||||||
@ -2056,7 +2315,7 @@ std::vector<BatchOperation> ExtractBatchOperations(const std::string& json) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Batch Operations Handler
|
// Batch Operations Handler
|
||||||
HttpResponse BatchOperationsHandler(const HttpRequest& request) {
|
HttpResponse BatchOperationsHandler(const HttpRequest& request) {
|
||||||
HttpResponse response;
|
HttpResponse response;
|
||||||
|
|
||||||
if (request.method != "POST") {
|
if (request.method != "POST") {
|
||||||
@ -2066,10 +2325,31 @@ HttpResponse BatchOperationsHandler(const HttpRequest& request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Parse batch operations request
|
// Parse batch operations request
|
||||||
BatchOperationsRequest batch_request;
|
BatchOperationsRequest batch_request;
|
||||||
|
std::string execution_id = ExtractJsonValue(request.body, "execution_id");
|
||||||
batch_request.software_type = ExtractJsonValue(request.body, "software_type");
|
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
|
// Validate software_type
|
||||||
if (batch_request.software_type.empty()) {
|
if (batch_request.software_type.empty()) {
|
||||||
@ -2091,8 +2371,15 @@ HttpResponse BatchOperationsHandler(const HttpRequest& request) {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute batch operations
|
// Execute batch operations
|
||||||
BatchOperationsResponse batch_result = BatchOperationManager::Instance().ExecuteBatchOperations(batch_request);
|
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
|
// Build response JSON
|
||||||
std::ostringstream json;
|
std::ostringstream json;
|
||||||
@ -2214,4 +2501,4 @@ extern "C" void user_terminate()
|
|||||||
KillTimer(NULL, timer_id);
|
KillTimer(NULL, timer_id);
|
||||||
timer_id = 0;
|
timer_id = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user