blob: 890d0e5299e59ec845d4f26913779386a8ec4742 [file] [edit]
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION &
* AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "coroutine.hpp"
#include "types.hpp"
#include "utils.hpp"
#include <xyz/openbmc_project/Logging/Entry/server.hpp>
#include <queue>
namespace utils
{
constexpr auto entityManagerService = "xyz.openbmc_project.EntityManager";
const std::string entityManagerServiceStr = "xyz.openbmc_project.EntityManager";
// Forward declaration for logging level type
using Level = sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level;
struct coGetDbusPropertyBase
{
const std::string service;
const std::string objectPath;
const std::string interface;
const std::string property;
bool setRetValueByProperty() noexcept;
virtual void setRetValue(const PropertyValue& value) = 0;
virtual void resetRetValue() = 0;
/** @brief Returning false to make await_suspend() to be called.
*/
bool await_ready() noexcept;
/** @brief Called by co_await operator before suspending coroutine. The
* method will send out NSM request message, register a call back function
* for the event when D-Bus method done.
*/
bool await_suspend(std::coroutine_handle<> handle) noexcept;
/** @brief Constructor of awaitable object to initialize necessary member
* variables.
*/
coGetDbusPropertyBase(const std::string& objectPath,
const std::string& property,
const std::string& interface,
const std::string& service = entityManagerService) :
service(service), objectPath(objectPath), interface(interface),
property(property)
{}
};
/** @struct coGetDbusProperty
*
* An awaitable object needed by co_await operator to get D-Bus Property value
* e.g.
* rc = co_await
* coGetDbusProperty<std::string>("/xyz/openbmc_project/inventory/system/chassis/HGX_GPU_SXM_1/HGX_GPU_SXM_1",
* "UUID", "xyz.openbmc_project.Configuration.NSM_Chassis",
* "xyz.openbmc_project.EntityManager");
*
* @tparam type - property data type
*/
template <typename type, typename = void>
struct coGetDbusProperty : coGetDbusPropertyBase, type
{
void setRetValue(const PropertyValue& value) override final
{
static_cast<type&>(*this) = std::get<type>(value);
}
void resetRetValue() override final
{
static_cast<type&>(*this) = type();
}
/** @brief Called by co_await operator to get return value when awaitable
* object completed.
*/
type await_resume() const noexcept
{
return static_cast<type>(*this);
}
coGetDbusProperty(const std::string& objectPath,
const std::string& property, const std::string& interface,
const std::string& service = entityManagerService) :
coGetDbusPropertyBase(objectPath, property, interface, service), type()
{
#ifdef COVERAGE_DISABLE_COROUTINES
setRetValueByProperty();
#endif // COVERAGE_DISABLE_COROUTINES
}
};
template <typename type>
struct coGetDbusProperty<type, std::enable_if_t<std::is_arithmetic_v<type> ||
std::is_enum_v<type>>> :
coGetDbusPropertyBase
{
/** @brief For keeping the return value.
*/
type ret;
void setRetValue(const PropertyValue& value) override final
{
ret = std::get<type>(value);
}
void resetRetValue() override final
{
ret = type();
}
/** @brief Called by co_await operator to get return value when awaitable
* object completed.
*/
type await_resume() const noexcept
{
return ret;
}
coGetDbusProperty(const std::string& objectPath,
const std::string& property, const std::string& interface,
const std::string& service = entityManagerService) :
coGetDbusPropertyBase(objectPath, property, interface, service), ret()
{
#ifdef COVERAGE_DISABLE_COROUTINES
setRetValueByProperty();
#endif // COVERAGE_DISABLE_COROUTINES
}
#ifdef COVERAGE_DISABLE_COROUTINES
operator type() const noexcept
{
return static_cast<type>(ret);
}
#endif // COVERAGE_DISABLE_COROUTINES
};
/** @struct coGetServiceMap
*
* An awaitable object needed by co_await operator to get service map which has
* the interfaces e.g. auto mapperResponse = co_await
* utils::coGetServiceMap(objPath, dbus::Interfaces{});
*
* @tparam type - property data type
*/
struct coGetServiceMap : MapperServiceMap
{
const std::string objectPath;
const dbus::Interfaces ifaceList;
/** @brief Returning false to make await_suspend() to be called.
*/
bool await_ready() noexcept;
/** @brief Called by co_await operator before suspending coroutine. The
* method will send out NSM request message, register a call back function
* for the event when D-Bus method done.
*/
bool await_suspend(std::coroutine_handle<> handle) noexcept;
/** @brief Called by co_await operator to get return value when awaitable
* object completed.
*/
MapperServiceMap await_resume() const noexcept
{
return static_cast<MapperServiceMap>(*this);
}
/** @brief Constructor of awaitable object to initialize necessary member
* variables.
*/
coGetServiceMap(const std::string& objectPath,
const dbus::Interfaces& ifaceList);
};
struct coGetAllDbusProperty : dbus::PropertyMap
{
const std::string service;
const std::string objectPath;
const std::string interface;
/** @brief Returning false to make await_suspend() to be called.
*/
bool await_ready() noexcept;
/** @brief Called by co_await operator before suspending coroutine. The
* method will send out NSM request message, register a call back function
* for the event when D-Bus method done.
*/
bool await_suspend(std::coroutine_handle<> handle) noexcept;
/** @brief Called by co_await operator to get return value when awaitable
* object completed.
*/
dbus::PropertyMap await_resume() const noexcept
{
return static_cast<dbus::PropertyMap>(*this);
}
/** @brief Constructor of awaitable object to initialize necessary member
* variables.
*/
coGetAllDbusProperty(const std::string& service,
const std::string& objectPath,
const std::string& interface = "");
};
/* @struct coLogEvent
*
* An awaitable object for async D-Bus logging operations
* e.g.
* bool success = co_await utils::coLogEvent(service, "MessageId", level, data);
*/
struct coLogEvent
{
const std::string service;
const std::string messageId;
const Level level;
const std::map<std::string, std::string> data;
bool success = false;
/** @brief Returning false to make await_suspend() to be called.
*/
bool await_ready() noexcept;
/** @brief Called by co_await operator before suspending coroutine.
*/
bool await_suspend(std::coroutine_handle<> handle) noexcept;
/** @brief Called by co_await operator to get return value when awaitable
* object completed.
*/
bool await_resume() const noexcept
{
return success;
}
/** @brief Constructor of awaitable object to initialize necessary member
* variables.
*/
coLogEvent(const std::string& svc, const std::string& msgId, Level lvl,
const std::map<std::string, std::string>& logData) :
service(svc), messageId(msgId), level(lvl), data(logData)
{}
#ifdef COVERAGE_DISABLE_COROUTINES
coLogEvent(bool value) :
service(""), messageId(""), level(Level::Informational), data{},
success(value)
{}
operator bool() const noexcept
{
return success;
}
#endif // COVERAGE_DISABLE_COROUTINES
};
/* @struct coDbusMethodCall
*
* A generic awaitable object for async D-Bus method calls with any data type
* e.g.
* bool success = co_await utils::coDbusMethodCall(
* service, objPath, interface, method, data);
*/
template <typename DataType>
struct coDbusMethodCall
{
const std::string service;
const std::string objectPath;
const std::string interface;
const std::string method;
const DataType data;
bool success = false;
bool await_ready() noexcept
{
return false;
}
bool await_suspend(std::coroutine_handle<> handle) noexcept
{
auto& asioConnection = utils::DBusHandler::getAsioConnection();
asioConnection->async_method_call(
[resumeHandle = handle,
&success = success](boost::system::error_code ec) {
success = !ec;
if (ec)
{
lg2::error("coDbusMethodCall failed: {ERROR}", "ERROR",
ec.message());
}
resumeHandle();
},
service.c_str(), objectPath.c_str(), interface.c_str(),
method.c_str(), data);
return true;
}
bool await_resume() const noexcept
{
return success;
}
coDbusMethodCall(const std::string& svc, const std::string& objPath,
const std::string& intf, const std::string& mtd,
const DataType& payload) :
service(svc), objectPath(objPath), interface(intf), method(mtd),
data(payload)
{}
#ifdef COVERAGE_DISABLE_COROUTINES
coDbusMethodCall(bool value) :
service(""), objectPath(""), interface(""), method(""), data{},
success(value)
{}
operator bool() const noexcept
{
return success;
}
#endif // COVERAGE_DISABLE_COROUTINES
};
} // namespace utils