Explorar o código

fix: stop re-parsing configSchema unguarded when recovering property order

The uiOrder block inside the configSchema case re-ran the field-start regex,
re-found the opening brace, re-ran jsLiteralToJson, and called
nlohmann::ordered_json::parse on the result with no exception handler - the
try/catch that guards every other parse in this function was lost when this
block was pulled out into the parse_schema_field lambda, since the lambda's
own guard only covers the nlohmann::json::parse call it makes, not this
second independent parse of the same text done outside it.

parse_schema_field now optionally hands back the exact JSON text it parsed
(raw_json), so the configSchema block reuses that instead of redoing the
regex search and jsLiteralToJson from scratch - removing the duplicated work
- and the ordered_json::parse call is wrapped in its own try/catch, so a
node whose schema is well-formed enough for the first parser but not the
second logs a warning and keeps its already-parsed schema, instead of an
uncaught nlohmann::json::exception taking the process down.
fszontagh hai 1 mes
pai
achega
45a213fa04
Modificáronse 1 ficheiros con 31 adicións e 18 borrados
  1. 31 18
      src/webserver/nodes/node_store.cpp

+ 31 - 18
src/webserver/nodes/node_store.cpp

@@ -371,7 +371,12 @@ StoredNode StoredNode::parseFromCode(const std::string& code, const std::string&
     // literal, or text jsLiteralToJson produced that nlohmann::json rejects -
     // is recorded in node.schema_parse_errors so migration can refuse to
     // store a degraded node instead of silently writing null.
-    auto parse_schema_field = [&](const char* field_name, nlohmann::json& out) -> std::string {
+    // raw_json, when given, receives the exact JSON text that was parsed for
+    // `out` - so a caller that needs the same text again (uiOrder below)
+    // reuses it instead of re-running the regex search and jsLiteralToJson
+    // from scratch.
+    auto parse_schema_field = [&](const char* field_name, nlohmann::json& out,
+                                   std::string* raw_json = nullptr) -> std::string {
         std::regex start_regex(std::string(R"(const\s+)") + field_name + R"(\s*=\s*)");
         std::smatch field_match;
         if (!std::regex_search(code, field_match, start_regex)) {
@@ -396,11 +401,15 @@ StoredNode StoredNode::parseFromCode(const std::string& code, const std::string&
             LOG_WARN("Failed to parse {} for {}: {}", field_name, node.id, e.what());
             return e.what();
         }
+        if (raw_json) {
+            *raw_json = std::move(jsonStr);
+        }
         return "";
     };
 
     {
-        std::string err = parse_schema_field("configSchema", node.config_schema);
+        std::string config_json_str;
+        std::string err = parse_schema_field("configSchema", node.config_schema, &config_json_str);
         if (!err.empty()) {
             node.schema_parse_errors.push_back("configSchema - " + err);
         } else if (!node.config_schema.is_null()) {
@@ -409,30 +418,34 @@ StoredNode StoredNode::parseFromCode(const std::string& code, const std::string&
             // nlohmann::json sorts an object's keys, so by the time a
             // schema reaches the editor "width" has drifted to the end
             // and "height" near the front, whatever the node author
-            // wrote. ordered_json keeps insertion order, so parsing a
-            // second time with it recovers the real order.
+            // wrote. ordered_json keeps insertion order, so parsing the
+            // same JSON text again with it recovers the real order.
             //
             // It is stored as an ARRAY rather than by keeping the whole
             // schema ordered, because the schema is written to the
             // database and read back, and nothing here controls whether
             // that round trip preserves an object's key order. An array
             // has an order by definition and survives any of it.
-            std::regex config_start_regex(R"(const\s+configSchema\s*=\s*)");
-            if (std::regex_search(code, match, config_start_regex)) {
-                size_t start_pos = match.position() + match.length();
-                size_t brace_pos = code.find('{', start_pos);
-                if (brace_pos != std::string::npos) {
-                    std::string jsonStr = jsLiteralToJson(code, brace_pos);
-                    auto ordered = nlohmann::ordered_json::parse(jsonStr);
-                    if (ordered.contains("properties") && ordered["properties"].is_object()) {
-                        auto ui_order = nlohmann::json::array();
-                        for (auto it = ordered["properties"].begin();
-                             it != ordered["properties"].end(); ++it) {
-                            ui_order.push_back(it.key());
-                        }
-                        node.config_schema["uiOrder"] = ui_order;
+            //
+            // config_json_str already parsed cleanly above (that is what
+            // made err empty), so this reparse of the identical text is not
+            // expected to fail - but nlohmann::ordered_json::parse still
+            // throws on malformed input like any other json::parse, so it
+            // stays behind a try/catch rather than trust that a second
+            // parser agrees with the first.
+            try {
+                auto ordered = nlohmann::ordered_json::parse(config_json_str);
+                if (ordered.contains("properties") && ordered["properties"].is_object()) {
+                    auto ui_order = nlohmann::json::array();
+                    for (auto it = ordered["properties"].begin();
+                         it != ordered["properties"].end(); ++it) {
+                        ui_order.push_back(it.key());
                     }
+                    node.config_schema["uiOrder"] = ui_order;
                 }
+            } catch (const nlohmann::json::exception& e) {
+                LOG_WARN("Failed to recover configSchema property order for {}: {}",
+                         node.id, e.what());
             }
         }
     }