annotator/example/include/health/ui/plugin_registry.hpp
Alexander Kobjolke 04b878f078 Initial version
2022-03-01 22:13:15 +01:00

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 */