#ifndef HEALTH_UI_PLUGIN_REGISTRY_HPP #define HEALTH_UI_PLUGIN_REGISTRY_HPP #include #include #include #include #include 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 library; // coverity[autosar_cpp14_m11_0_1_violation] we do not need a class std::unique_ptr api; // coverity[autosar_cpp14_m11_0_1_violation] we do not need a class std::unique_ptr 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 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 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 { 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 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 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 participant, infra::log::LoggerPtr logger) : m_participant { std::move(participant) } , m_logger { std::move(logger) } { } [[nodiscard]] std::shared_ptr get_participant() const override { return m_participant; } [[nodiscard]] ::infra::log::LoggerPtr get_logger() const override { return m_logger; } private: std::shared_ptr m_participant; infra::log::LoggerPtr m_logger; }; return std::make_unique(m_participant, m_logger->get_child(name)); } /** * Main functionality for our class */ virtual util::ErrorOr load_file(const std::filesystem::path& file) const { auto lib { m_loader.load(file) }; if (const auto version { lib->get("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 load_plugin(const std::filesystem::path& file, std::unique_ptr lib) const { m_logger->debug("Trying to load compatible plugin from '{}'", file); const auto plugin_info { lib->get("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 { 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 m_participant; std::list m_plugins; }; } #endif /* HEALTH_UI_PLUGIN_REGISTRY_HPP */