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