mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-30 14:22:07 +00:00
fix: generate setting id if it is empty for 409 tombstone
This commit is contained in:
@@ -4940,6 +4940,7 @@ void GUI_App::on_http_error(wxCommandEvent &evt)
|
|||||||
// Parse the conflict body to extract the error code and server profile id
|
// Parse the conflict body to extract the error code and server profile id
|
||||||
int conflict_code = 0;
|
int conflict_code = 0;
|
||||||
std::string conflict_setting_id;
|
std::string conflict_setting_id;
|
||||||
|
std::string conflict_preset_name;
|
||||||
try {
|
try {
|
||||||
json conflict_body = json::parse(body_str);
|
json conflict_body = json::parse(body_str);
|
||||||
if (conflict_body.contains("code"))
|
if (conflict_body.contains("code"))
|
||||||
@@ -4947,9 +4948,15 @@ void GUI_App::on_http_error(wxCommandEvent &evt)
|
|||||||
if (conflict_body.contains("server_profile") && conflict_body["server_profile"].contains("id")
|
if (conflict_body.contains("server_profile") && conflict_body["server_profile"].contains("id")
|
||||||
&& conflict_body["server_profile"]["id"].is_string())
|
&& conflict_body["server_profile"]["id"].is_string())
|
||||||
conflict_setting_id = conflict_body["server_profile"]["id"].get<std::string>();
|
conflict_setting_id = conflict_body["server_profile"]["id"].get<std::string>();
|
||||||
|
// The local preset name is injected into the conflict body by the agent (sync_push),
|
||||||
|
// since the server response itself omits it for tombstone (-3) conflicts.
|
||||||
|
if (conflict_body.contains("name") && conflict_body["name"].is_string())
|
||||||
|
conflict_preset_name = conflict_body["name"].get<std::string>();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
BOOST_LOG_TRIVIAL(warning) << "Failed to parse 409 conflict body.";
|
BOOST_LOG_TRIVIAL(warning) << "Failed to parse 409 conflict body.";
|
||||||
}
|
}
|
||||||
|
// Capture the user id up front so the force-push closure does not have to touch m_agent.
|
||||||
|
std::string conflict_user_id = m_agent ? m_agent->get_user_id() : std::string();
|
||||||
auto* plater = wxGetApp().plater();
|
auto* plater = wxGetApp().plater();
|
||||||
if (plater != nullptr && wxGetApp().imgui()->display_initialized()) {
|
if (plater != nullptr && wxGetApp().imgui()->display_initialized()) {
|
||||||
std::string text;
|
std::string text;
|
||||||
@@ -4984,7 +4991,7 @@ void GUI_App::on_http_error(wxCommandEvent &evt)
|
|||||||
restart_sync_user_preset();
|
restart_sync_user_preset();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
[this, conflict_setting_id](wxEvtHandler*) {
|
[this, conflict_setting_id, conflict_preset_name, conflict_user_id](wxEvtHandler*) {
|
||||||
if (mainframe == nullptr)
|
if (mainframe == nullptr)
|
||||||
return false;
|
return false;
|
||||||
MessageDialog
|
MessageDialog
|
||||||
@@ -4994,7 +5001,13 @@ void GUI_App::on_http_error(wxCommandEvent &evt)
|
|||||||
if (dlg.ShowModal() != wxID_YES)
|
if (dlg.ShowModal() != wxID_YES)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
force_push_conflicting_preset(conflict_setting_id);
|
std::string setting_id = conflict_setting_id;
|
||||||
|
if (setting_id.empty()) {
|
||||||
|
setting_id = OrcaCloudServiceAgent::generate_uuid_for_setting_id(conflict_preset_name, conflict_user_id);
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "conflict setting id empty, generated one: " << setting_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
force_push_conflicting_preset(setting_id);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,24 +101,6 @@ std::string resolve_display_name(
|
|||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string generate_uuid_for_setting_id(const std::string& name, const std::string& user_id = "")
|
|
||||||
{
|
|
||||||
if (name.empty()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mix user_id into the hashed input so two different users generating a setting_id
|
|
||||||
// for an identically-named preset get distinct UUIDs. Without this, the cloud's ID
|
|
||||||
// space collides across accounts and the second user's create gets HTTP 409 with
|
|
||||||
// server_profile=null on every sync (the foreign owner's record is not exposed).
|
|
||||||
static const boost::uuids::uuid orca_namespace =
|
|
||||||
boost::uuids::string_generator()("f47ac10b-58cc-4372-a567-0e02b2c3d479");
|
|
||||||
|
|
||||||
boost::uuids::name_generator_sha1 gen(orca_namespace);
|
|
||||||
boost::uuids::uuid id = user_id.empty() ? gen(name) : gen(user_id + "/" + name);
|
|
||||||
return boost::uuids::to_string(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64url_encode(const std::vector<unsigned char>& data)
|
std::string base64url_encode(const std::vector<unsigned char>& data)
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out;
|
||||||
@@ -412,6 +394,24 @@ OrcaCloudServiceAgent::~OrcaCloudServiceAgent()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string OrcaCloudServiceAgent::generate_uuid_for_setting_id(const std::string& name, const std::string& user_id)
|
||||||
|
{
|
||||||
|
if (name.empty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mix user_id into the hashed input so two different users generating a setting_id
|
||||||
|
// for an identically-named preset get distinct UUIDs. Without this, the cloud's ID
|
||||||
|
// space collides across accounts and the second user's create gets HTTP 409 with
|
||||||
|
// server_profile=null on every sync (the foreign owner's record is not exposed).
|
||||||
|
static const boost::uuids::uuid orca_namespace =
|
||||||
|
boost::uuids::string_generator()("f47ac10b-58cc-4372-a567-0e02b2c3d479");
|
||||||
|
|
||||||
|
boost::uuids::name_generator_sha1 gen(orca_namespace);
|
||||||
|
boost::uuids::uuid id = user_id.empty() ? gen(name) : gen(user_id + "/" + name);
|
||||||
|
return boost::uuids::to_string(id);
|
||||||
|
}
|
||||||
|
|
||||||
void OrcaCloudServiceAgent::configure_urls(AppConfig* app_config)
|
void OrcaCloudServiceAgent::configure_urls(AppConfig* app_config)
|
||||||
{
|
{
|
||||||
if (!app_config) return;
|
if (!app_config) return;
|
||||||
@@ -1250,8 +1250,10 @@ SyncPushResult OrcaCloudServiceAgent::sync_push(const std::string& profile_id,
|
|||||||
|
|
||||||
if (http_code == 409) {
|
if (http_code == 409) {
|
||||||
// Conflict - parse server version
|
// Conflict - parse server version
|
||||||
|
nlohmann::json err_body;
|
||||||
try {
|
try {
|
||||||
auto json = nlohmann::json::parse(response);
|
auto json = nlohmann::json::parse(response);
|
||||||
|
err_body = json;
|
||||||
if (json.is_null()) {
|
if (json.is_null()) {
|
||||||
result.server_deleted = true;
|
result.server_deleted = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -1261,6 +1263,13 @@ SyncPushResult OrcaCloudServiceAgent::sync_push(const std::string& profile_id,
|
|||||||
result.server_version.updated_time = profile_data.value(ORCA_JSON_KEY_UPDATE_TIME, 0);
|
result.server_version.updated_time = profile_data.value(ORCA_JSON_KEY_UPDATE_TIME, 0);
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
|
// Surface the conflict via the http-error callback with the local preset name injected.
|
||||||
|
// The raw server body omits the name for tombstone (-3) conflicts (server_profile is null),
|
||||||
|
// but the GUI needs it to regenerate the deterministic setting_id for a force push.
|
||||||
|
if (!err_body.is_object())
|
||||||
|
err_body = nlohmann::json::object();
|
||||||
|
err_body["name"] = name;
|
||||||
|
invoke_http_error_callback(409, err_body.dump());
|
||||||
result.error_message = response;
|
result.error_message = response;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1937,7 +1946,10 @@ int OrcaCloudServiceAgent::http_post(const std::string& path, const std::string&
|
|||||||
if (response_body) *response_body = res.body;
|
if (response_body) *response_body = res.body;
|
||||||
if (http_code) *http_code = res.status;
|
if (http_code) *http_code = res.status;
|
||||||
|
|
||||||
if (!suppress && (!res.success || res.status >= 400)) {
|
// 409 is a push-only domain conflict; sync_push re-fires the error callback with the
|
||||||
|
// local preset name injected (the raw server body omits it for tombstone conflicts),
|
||||||
|
// so skip the generic nameless auto-fire here to avoid a duplicate, nameless event.
|
||||||
|
if (!suppress && (!res.success || res.status >= 400) && res.status != 409) {
|
||||||
invoke_http_error_callback(res.status, res.body);
|
invoke_http_error_callback(res.status, res.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -300,6 +300,8 @@ public:
|
|||||||
bool set_user_session(const nlohmann::json& session_json, bool notify_login = true);
|
bool set_user_session(const nlohmann::json& session_json, bool notify_login = true);
|
||||||
void clear_session();
|
void clear_session();
|
||||||
|
|
||||||
|
static std::string generate_uuid_for_setting_id(const std::string& name, const std::string& user_id = "");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Sync protocol helpers
|
// Sync protocol helpers
|
||||||
int sync_pull(
|
int sync_pull(
|
||||||
|
|||||||
Reference in New Issue
Block a user