mctp: refactor matching logic and priming query

Refactored the MCTP matching logic to remove code duplication and
improve maintainability.

1. Extracted the physical topology extraction logic from NVMeSensorMain
   into a shared helper function `extractBusInfo` in MctpUtil. This
   removed identical duplicate extraction loops that were used for both
   the sensor configuration and the cached endpoint configurations.

2. Merged the cache priming D-Bus query for associations with the
   `performEmConfigQuery` function in MctpUtil. This eliminated the
   redundant `GetManagedObjects` call and inline property parsing,
   ensuring all EM queries follow the same execution and state tracking
   path.

3. Fixed inconsistent state setting in the cache priming loop to ensure
   we don't trigger redundant queries on startup for existing devices.

Change-Id: I6d5495e4be2b864cde90b4dfec805b2815e3e395
Google-Bug-Id: 490106522
Signed-off-by: Hao Jiang <jianghao@google.com>
diff --git a/src/MctpUtil.cpp b/src/MctpUtil.cpp
index 106cb10..add107a 100644
--- a/src/MctpUtil.cpp
+++ b/src/MctpUtil.cpp
@@ -1,5 +1,7 @@
 #include "MctpUtil.hpp"
 
+#include "absl/strings/match.h"
+
 #include "Utils.hpp"
 #include "VariantVisitors.hpp"
 
@@ -238,42 +240,16 @@
                                                               suffix.length());
                 }
 
-                // Now query the EM config path for its properties
-                std::filesystem::path p(emConfigPath);
-                std::string parentPath = p.parent_path().string();
+                auto& state = endpointStates[endpointPath];
 
-                conn->async_method_call(
-                    [endpointPath,
-                     emConfigPath](const boost::system::error_code& ec,
-                                   const ManagedObjectType& objects) {
-                    if (ec)
-                    {
-                        lg2::error(
-                            "Failed to get managed objects for {PATH}: {ERROR}",
-                            "PATH", emConfigPath, "ERROR", ec.message());
-                        return;
-                    }
+                if (state.querying)
+                {
+                    state.state = State::Add;
+                    return;
+                }
 
-                    auto objIt = objects.find(
-                        sdbusplus::message::object_path(emConfigPath));
-                    if (objIt == objects.end())
-                    {
-                        lg2::warning(
-                            "EM config path {PATH} not found in managed objects",
-                            "PATH", emConfigPath);
-                        return;
-                    }
-
-                    if (!objIt->second.empty())
-                    {
-                        lg2::info(
-                            "Primed match for endpoint {ENDPOINT} with config from {PATH}",
-                            "ENDPOINT", endpointPath, "PATH", emConfigPath);
-                        mctpEndpointConfigMap[endpointPath] = objIt->second;
-                    }
-                },
-                    "xyz.openbmc_project.EntityManager", parentPath,
-                    "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+                state.querying = true;
+                performEmConfigQuery(conn, endpointPath, emConfigPath);
             },
                 "xyz.openbmc_project.ObjectMapper", path,
                 "org.freedesktop.DBus.Properties", "Get",
@@ -285,3 +261,45 @@
         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
         "/au/com/codeconstruct/mctp1", 0, associationInterfaces);
 }
+
+BusInfo extractBusInfo(const SensorData& configData)
+{
+    BusInfo busInfo;
+    auto extractProp = [](const auto& properties, BusInfo& info,
+                          const std::string& key) {
+        auto it = properties.find(key);
+        if (it != properties.end())
+        {
+            info[key] = std::visit(VariantToStringVisitor(), it->second);
+        }
+    };
+
+    for (const auto& [intf, props] : configData)
+    {
+        if (absl::StrContains(intf,
+                              "xyz.openbmc_project.Configuration.BusInfo"))
+        {
+            std::string busType;
+            auto it = props.find("BusType");
+            if (it != props.end())
+            {
+                busType = std::visit(VariantToStringVisitor(), it->second);
+            }
+
+            if (busType == "USB")
+            {
+                extractProp(props, busInfo, "RootHubPath");
+                extractProp(props, busInfo, "Port");
+                extractProp(props, busInfo, "Configuration");
+                extractProp(props, busInfo, "InterfaceNum");
+
+                busInfo["BusType"] = busType;
+            }
+            else if (!busType.empty())
+            {
+                lg2::warning("Unsupported BusType {TYPE}", "TYPE", busType);
+            }
+        }
+    }
+    return busInfo;
+}
diff --git a/src/MctpUtil.hpp b/src/MctpUtil.hpp
index 580f7a0..b34fd86 100644
--- a/src/MctpUtil.hpp
+++ b/src/MctpUtil.hpp
@@ -18,3 +18,5 @@
 
 void setupMctpEndpointListener(
     const std::shared_ptr<sdbusplus::asio::connection>& conn);
+
+BusInfo extractBusInfo(const SensorData& configData);
diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
index c89eafc..584fd89 100644
--- a/src/NVMeSensorMain.cpp
+++ b/src/NVMeSensorMain.cpp
@@ -356,49 +356,7 @@
                 if (*nvmeProtocol == "mi_mctp")
                 {
                     BusInfo busInfo;
-                    auto extractProp = [](const auto& properties, BusInfo& info,
-                                          const std::string& key) {
-                        auto it = properties.find(key);
-                        if (it != properties.end())
-                        {
-                            info[key] = std::visit(VariantToStringVisitor(),
-                                                   it->second);
-                        }
-                    };
-
-                    for (const auto& [intf, props] : configData)
-                    {
-                        if (absl::StrContains(
-                                intf,
-                                "xyz.openbmc_project.Configuration.BusInfo"))
-                        {
-                            std::string busType;
-                            auto it = props.find("BusType");
-                            if (it != props.end())
-                            {
-                                busType = std::visit(VariantToStringVisitor(),
-                                                     it->second);
-                            }
-
-                            if (busType == "USB")
-                            {
-                                extractProp(props, busInfo, "RootHubPath");
-                                extractProp(props, busInfo, "Port");
-                                extractProp(props, busInfo, "Configuration");
-                                extractProp(props, busInfo, "InterfaceNum");
-
-                                busInfo["BusType"] = busType;
-                            }
-                            else if (!busType.empty())
-                            {
-                                lg2::warning(
-                                    "Unsupported BusType {TYPE} for {PATH}",
-                                    "TYPE", busType, "PATH",
-                                    nvmeObjectPath.str);
-                            }
-                        }
-                    }
-
+                    busInfo = extractBusInfo(configData);
                     if (busInfo.empty())
                     {
                         lg2::error("Missing BusInfo for mi_mctp device {PATH}",
@@ -409,21 +367,7 @@
                     std::string endpointPath;
                     for (const auto& [epPath, epConfig] : mctpEndpointConfigMap)
                     {
-                        BusInfo epBusInfo;
-                        for (const auto& [intf, props] : epConfig)
-                        {
-                            extractProp(props, epBusInfo, "RootHubPath");
-                            extractProp(props, epBusInfo, "Port");
-                            extractProp(props, epBusInfo, "Configuration");
-                            extractProp(props, epBusInfo, "InterfaceNum");
-
-                            if (epBusInfo.count("RootHubPath") > 0 &&
-                                epBusInfo.count("BusType") == 0)
-                            {
-                                epBusInfo["BusType"] = "USB";
-                            }
-                        }
-
+                        BusInfo epBusInfo = extractBusInfo(epConfig);
                         if (epBusInfo == busInfo)
                         {
                             endpointPath = epPath;