view libirccd/irccd/daemon/plugin_service.hpp @ 613:0c7241258289

Docs: pet doxygen
author David Demelier <markand@malikania.fr>
date Fri, 15 Dec 2017 17:08:01 +0100
parents 986ed3a7575d
children 27587ff92a64
line wrap: on
line source

/*
 * plugin_service.hpp -- plugin service
 *
 * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef IRCCD_DAEMON_PLUGIN_SERVICE_HPP
#define IRCCD_DAEMON_PLUGIN_SERVICE_HPP

/**
 * \file plugin_service.hpp
 * \brief Plugin service.
 */

#include <cassert>
#include <memory>
#include <string>
#include <vector>

#include "plugin.hpp"

namespace irccd {

class irccd;
class config;

/**
 * \brief Manage plugins.
 * \ingroup services
 */
class plugin_service {
private:
    irccd& irccd_;
    std::vector<std::shared_ptr<plugin>> plugins_;
    std::vector<std::unique_ptr<plugin_loader>> loaders_;

public:
    /**
     * Create the plugin service.
     *
     * \param irccd the irccd instance
     */
    plugin_service(irccd& irccd) noexcept;

    /**
     * Destroy plugins.
     */
    ~plugin_service();

    /**
     * Get the list of plugins.
     *
     * \return the list of plugins
     */
    inline const std::vector<std::shared_ptr<plugin>>& list() const noexcept
    {
        return plugins_;
    }

    /**
     * Check if a plugin is loaded.
     *
     * \param name the plugin id
     * \return true if has plugin
     */
    bool has(const std::string& name) const noexcept;

    /**
     * Get a loaded plugin or null if not found.
     *
     * \param name the plugin id
     * \return the plugin or empty one if not found
     */
    std::shared_ptr<plugin> get(const std::string& name) const noexcept;

    /**
     * Find a loaded plugin.
     *
     * \param name the plugin id
     * \return the plugin
     * \throws std::out_of_range if not found
     */
    std::shared_ptr<plugin> require(const std::string& name) const;

    /**
     * Add the specified plugin to the registry.
     *
     * \pre plugin != nullptr
     * \param plugin the plugin
     * \note the plugin is only added to the list, no action is performed on it
     */
    void add(std::shared_ptr<plugin> plugin);

    /**
     * Add a loader.
     *
     * \param loader the loader
     */
    void add_loader(std::unique_ptr<plugin_loader> loader);

    /**
     * Get the configuration for the specified plugin.
     *
     * \return the configuration
     */
    plugin_config config(const std::string& id);

    /**
     * Get the formats for the specified plugin.
     *
     * \return the formats
     */
    plugin_formats formats(const std::string& id);

    /**
     * Get the paths for the specified plugin.
     *
     * If none is defined, return the default ones.
     *
     * \return the paths
     */
    plugin_paths paths(const std::string& id);

    /**
     * Generic function for opening the plugin at the given path.
     *
     * This function will search for every pluginLoader and call open() on it,
     * the first one that success will be returned.
     *
     * \param id the plugin id
     * \param path the path to the file
     * \return the plugin or nullptr on failures
     */
    std::shared_ptr<plugin> open(const std::string& id,
                                 const std::string& path);

    /**
     * Generic function for finding a plugin.
     *
     * \param id the plugin id
     * \return the plugin or nullptr on failures
     */
    std::shared_ptr<plugin> find(const std::string& id);

    /**
     * Convenient wrapper that loads a plugin, call onLoad and add it to the
     * registry.
     *
     * Any errors are printed using logger.
     *
     * \param name the name
     * \param path the optional path (searched if empty)
     */
    void load(std::string name, std::string path = "");

    /**
     * Unload a plugin and remove it.
     *
     * \param name the plugin id
     */
    void unload(const std::string& name);

    /**
     * Reload a plugin by calling onReload.
     *
     * \param name the plugin name
     * \throw std::exception on failures
     */
    void reload(const std::string& name);

    /**
     * Call a plugin function and throw an exception with the following errors:
     *
     *   - plugin_error::not_found if not loaded
     *   - plugin_error::exec_error if function failed
     *
     * \pre plugin != nullptr
     * \param plugin the plugin
     * \param fn the plugin member function (pointer to member)
     * \param args the arguments to pass
     */
    template <typename Func, typename... Args>
    void exec(std::shared_ptr<plugin> plugin, Func fn, Args&&... args)
    {
        assert(plugin);

        // TODO: replace with C++17 std::invoke.
        try {
            ((*plugin).*(fn))(std::forward<Args>(args)...);
        } catch (const std::exception& ex) {
            throw plugin_error(plugin_error::exec_error, plugin->name(), ex.what());
        } catch (...) {
            throw plugin_error(plugin_error::exec_error, plugin->name());
        }
    }

    /**
     * Overloaded function.
     *
     * \param name the plugin name
     * \param fn the plugin member function (pointer to member)
     * \param args the arguments to pass
     */
    template <typename Func, typename... Args>
    void exec(const std::string& name, Func fn, Args&&... args)
    {
        auto plugin = find(name);

        if (!plugin)
            throw plugin_error(plugin_error::not_found, plugin->name());

        exec(plugin, fn, std::forward<Args>(args)...);
    }

    /**
     * Load all plugins.
     *
     * \param cfg the config
     */
    void load(const class config& cfg) noexcept;
};

} // !irccd

#endif // !IRCCD_DAEMON_PLUGIN_SERVICE_HPP