144 lines
5.4 KiB
C++
144 lines
5.4 KiB
C++
#ifndef HEALTH_UI_PLUGIN_REGISTRY_HPP
|
|
#define HEALTH_UI_PLUGIN_REGISTRY_HPP
|
|
|
|
#include <list>
|
|
|
|
#include <infra/log.hpp>
|
|
|
|
#include <util/shared_object.hpp>
|
|
|
|
#include <health/ui/plugin_api.hpp>
|
|
#include <health/ui/error_or.hpp>
|
|
|
|
namespace health::ui {
|
|
// coverity[autosar_cpp14_a11_0_1_violation] we do not need a class
|
|
struct LoadedPlugin {
|
|
// coverity[autosar_cpp14_m11_0_1_violation] we do not need a class
|
|
std::string name;
|
|
// coverity[autosar_cpp14_m11_0_1_violation] we do not need a class
|
|
std::filesystem::path file;
|
|
// coverity[autosar_cpp14_m11_0_1_violation] we do not need a class
|
|
std::unique_ptr<util::shared::Library> library;
|
|
// coverity[autosar_cpp14_m11_0_1_violation] we do not need a class
|
|
std::unique_ptr<health::ui::PluginApi> api;
|
|
// coverity[autosar_cpp14_m11_0_1_violation] we do not need a class
|
|
std::unique_ptr<health::ui::Adapter> adapter;
|
|
};
|
|
|
|
class PluginRegistry : public Adapter {
|
|
public:
|
|
// coverity[autosar_cpp14_a8_4_7_violation : FALSE] parameter gets moved
|
|
PluginRegistry(const util::shared::Loader& loader, infra::log::LoggerPtr logger, std::shared_ptr<asap::Participant> participant)
|
|
: m_loader { loader }
|
|
, m_logger { std::move(logger) }
|
|
, m_participant { std::move(participant) }
|
|
, m_plugins {}
|
|
{
|
|
}
|
|
|
|
[[nodiscard]] bool is_compatible(const Version our, const Version their) const
|
|
{
|
|
return is_compatible_impl(our, their);
|
|
}
|
|
|
|
// load plugin(s) from the given path
|
|
//
|
|
// NB: we currently do not support loading plugins from a directory
|
|
util::ErrorOr<std::string> load(const std::filesystem::path& path)
|
|
{
|
|
// coverity[autosar_cpp14_a5_1_4_violation : FALSE] objects get moved
|
|
return load_impl(path).and_then([this](LoadedPlugin& p) -> util::ErrorOr<std::string> {
|
|
const auto plugin_name { p.name };
|
|
m_logger->info("Loaded plugin '{}' from '{}'", p.name, p.file);
|
|
m_plugins.push_back(std::move(p));
|
|
return { plugin_name };
|
|
});
|
|
}
|
|
|
|
private:
|
|
// coverity[autosar_cpp14_a7_1_8_violation : FALSE] nodiscard ignored
|
|
[[nodiscard]] virtual bool is_compatible_impl(const Version our, const Version their) const
|
|
{
|
|
return our == their; // be conservative right now
|
|
}
|
|
|
|
virtual util::ErrorOr<LoadedPlugin> load_impl(const std::filesystem::path& path) const
|
|
{
|
|
// we currently do not support loading directories, so just delegate to load_file for now
|
|
return load_file(path);
|
|
}
|
|
|
|
std::unique_ptr<PluginApi> create_api(const std::string& name) const
|
|
{
|
|
class PluginApiImpl : public PluginApi {
|
|
public:
|
|
// coverity[autosar_cpp14_a8_4_7_violation : FALSE] parameter gets moved
|
|
PluginApiImpl(std::shared_ptr<asap::Participant> participant, infra::log::LoggerPtr logger)
|
|
: m_participant { std::move(participant) }
|
|
, m_logger { std::move(logger) }
|
|
{
|
|
}
|
|
|
|
[[nodiscard]] std::shared_ptr<asap::Participant> get_participant() const override
|
|
{
|
|
return m_participant;
|
|
}
|
|
|
|
[[nodiscard]] ::infra::log::LoggerPtr get_logger() const override
|
|
{
|
|
return m_logger;
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<asap::Participant> m_participant;
|
|
infra::log::LoggerPtr m_logger;
|
|
};
|
|
|
|
return std::make_unique<PluginApiImpl>(m_participant, m_logger->get_child(name));
|
|
}
|
|
|
|
/**
|
|
* Main functionality for our class
|
|
*/
|
|
virtual util::ErrorOr<LoadedPlugin> load_file(const std::filesystem::path& file) const
|
|
{
|
|
auto lib { m_loader.load(file) };
|
|
if (const auto version { lib->get<Version>("health_ui_version") }; !is_compatible(health::ui::PLUGIN_API_VERSION, version)) {
|
|
return { std::make_error_code(std::errc::protocol_not_supported), "plugin has an incompatible version" };
|
|
} else {
|
|
return load_plugin(file, std::move(lib));
|
|
}
|
|
}
|
|
|
|
// coverity[autosar_cpp14_a8_4_7_violation : FALSE] move semantics
|
|
virtual util::ErrorOr<LoadedPlugin> load_plugin(const std::filesystem::path& file, std::unique_ptr<util::shared::Library> lib) const
|
|
{
|
|
m_logger->debug("Trying to load compatible plugin from '{}'", file);
|
|
const auto plugin_info { lib->get<PluginInfo*>("health_ui_info") };
|
|
std::string name { plugin_info->name };
|
|
|
|
auto api { create_api(name) };
|
|
|
|
// coverity[autosar_cpp14_a5_1_4_violation : FALSE] objects get moved
|
|
return plugin_info->create(*api).and_then([&name, &file, &lib, &api](AdapterPtr& adapter) -> util::ErrorOr<LoadedPlugin> {
|
|
return LoadedPlugin { std::move(name), file, std::move(lib), std::move(api), std::move(adapter) };
|
|
});
|
|
}
|
|
|
|
void update_internal(const ::health::Snapshot& system_state, const ::health::monitoring::HealthData& health_data) override
|
|
{
|
|
m_logger->debug("Updating {} ui-adapters...", m_plugins.size());
|
|
for (const auto& plugin : m_plugins) {
|
|
m_logger->trace("Updating '{}'...", plugin.name);
|
|
plugin.adapter->update(system_state, health_data);
|
|
}
|
|
}
|
|
|
|
const util::shared::Loader& m_loader;
|
|
infra::log::LoggerPtr m_logger;
|
|
std::shared_ptr<asap::Participant> m_participant;
|
|
std::list<LoadedPlugin> m_plugins;
|
|
};
|
|
}
|
|
|
|
#endif /* HEALTH_UI_PLUGIN_REGISTRY_HPP */
|