view libirccd-daemon/irccd/daemon/plugin.hpp @ 847:a23b7b574ed2

irccd: rename [format] section to [templates], closes #1671
author David Demelier <markand@malikania.fr>
date Wed, 10 Jul 2019 20:10:00 +0200
parents 06cc2f95f479
children 659be263703e
line wrap: on
line source

/*
 * plugin.hpp -- irccd JavaScript plugin interface
 *
 * Copyright (c) 2013-2019 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_HPP
#define IRCCD_DAEMON_PLUGIN_HPP

/**
 * \file plugin.hpp
 * \brief irccd plugins
 */

#include <irccd/sysconfig.hpp>

#include <memory>
#include <string>
#include <string_view>
#include <system_error>
#include <unordered_map>
#include <vector>

namespace irccd::daemon {

class bot;

struct connect_event;
struct disconnect_event;
struct invite_event;
struct join_event;
struct kick_event;
struct me_event;
struct message_event;
struct mode_event;
struct names_event;
struct nick_event;
struct notice_event;
struct part_event;
struct topic_event;
struct whois_event;

/**
 * \ingroup plugins
 * \brief Abstract plugin.
 *
 * A plugin is identified by name and can be loaded and unloaded at runtime.
 */
class plugin : public std::enable_shared_from_this<plugin> {
public:
	/**
	 * Map for key/value pairs.
	 *
	 * Used in options, templates and paths.
	 */
	using map = std::unordered_map<std::string, std::string>;

private:
	std::string id_;

public:
	/**
	 * Construct a plugin.
	 *
	 * \pre id must be a valid identifier
	 * \param id the plugin id
	 */
	plugin(std::string id) noexcept;

	/**
	 * Temporary, close all timers.
	 */
	virtual ~plugin() = default;

	/**
	 * Get user unique id.
	 *
	 * \return the plugin id
	 */
	auto get_id() const noexcept -> const std::string&;

	/**
	 * Get the plugin name.
	 *
	 * \return the plugin name
	 */
	virtual auto get_name() const noexcept -> std::string_view = 0;

	/**
	 * Get the author.
	 *
	 * \return the author
	 */
	virtual auto get_author() const noexcept -> std::string_view;

	/**
	 * Get the license.
	 *
	 * \return the license
	 */
	virtual auto get_license() const noexcept -> std::string_view;

	/**
	 * Get the summary.
	 *
	 * \return the summary
	 */
	virtual auto get_summary() const noexcept -> std::string_view;

	/**
	 * Get the version.
	 *
	 * \return the version
	 */
	virtual auto get_version() const noexcept -> std::string_view;

	/**
	 * Get all options.
	 *
	 * \return options
	 */
	virtual auto get_options() const -> map;

	/**
	 * Set all options.
	 *
	 * \param map the options
	 */
	virtual void set_options(const map& map);

	/**
	 * Get all templates.
	 *
	 * \return the templates
	 */
	virtual auto get_templates() const -> map;

	/**
	 * Set all templates.
	 *
	 * \param map the templates
	 */
	virtual void set_templates(const map& map);

	/**
	 * Get all paths.
	 *
	 * \return paths
	 */
	virtual auto get_paths() const -> map;

	/**
	 * Set all paths.
	 *
	 * \param map the paths
	 */
	virtual void set_paths(const map& map);

	/**
	 * On channel message. This event will call onMessage or
	 * onCommand if the messages starts with the command character
	 * plus the plugin name.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_command(bot& bot, const message_event& event);

	/**
	 * On successful connection.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_connect(bot& bot, const connect_event& event);

	/**
	 * On disconnection.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_disconnect(bot& bot, const disconnect_event& event);

	/**
	 * On invitation.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_invite(bot& bot, const invite_event& event);

	/**
	 * On join.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_join(bot& bot, const join_event& event);

	/**
	 * On kick.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_kick(bot& bot, const kick_event& event);

	/**
	 * On load.
	 *
	 * \param bot the irccd instance
	 */
	virtual void handle_load(bot& bot);

	/**
	 * On channel message.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_message(bot& bot, const message_event& event);

	/**
	 * On CTCP Action.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_me(bot& bot, const me_event& event);

	/**
	 * On user mode change.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_mode(bot& bot, const mode_event& event);

	/**
	 * On names listing.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_names(bot& bot, const names_event& event);

	/**
	 * On nick change.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_nick(bot& bot, const nick_event& event);

	/**
	 * On user notice.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_notice(bot& bot, const notice_event& event);

	/**
	 * On part.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_part(bot& bot, const part_event& event);

	/**
	 * On reload.
	 *
	 * \param bot the irccd instance
	 */
	virtual void handle_reload(bot& bot);

	/**
	 * On topic change.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_topic(bot& bot, const topic_event& event);

	/**
	 * On unload.
	 *
	 * \param bot the irccd instance
	 */
	virtual void handle_unload(bot& bot);

	/**
	 * On whois information.
	 *
	 * \param bot the irccd instance
	 * \param event the event
	 */
	virtual void handle_whois(bot& bot, const whois_event& event);
};

/**
 * \ingroup plugins
 * \brief Abstract interface for searching plugins.
 *
 * This class is used to make loading of plugins extensible, the plugin_service
 * knows some predefined plugins loaders and use them to search for available
 * plugins.
 *
 * This makes easier to implement new plugins or new ways of loading them.
 *
 * \see dynlib_plugin_loader
 * \see js_plugin_loader
 */
class plugin_loader {
private:
	std::vector<std::string> directories_;
	std::vector<std::string> extensions_;

public:
	/**
	 * Construct the loader with a predefined set of directories and
	 * extensions.
	 *
	 * If directories is not specified, a sensible default list of system
	 * and user paths are searched.
	 *
	 * \pre !extensions.empty()
	 * \param directories optional list of directories to search
	 * \param extensions optional list of extensions
	 */
	plugin_loader(std::vector<std::string> directories = {},
	              std::vector<std::string> extensions = {}) noexcept;

	/**
	 * Virtual destructor defaulted.
	 */
	virtual ~plugin_loader() = default;

	/**
	 * Tells if the plugin should be opened by checking file extension.
	 *
	 * \param path the path
	 * \return true if the extension matches
	 */
	virtual auto is_supported(std::string_view path) noexcept -> bool;

	/**
	 * Try to open the plugin specified by path.
	 *
	 * The implementation must test if the plugin is suitable for opening, by
	 * testing extension for example.
	 *
	 * \param id the plugin identifier
	 * \param file the file path
	 * \return the plugin
	 * \throw plugin_error on errors
	 */
	virtual auto open(std::string_view id, std::string_view file) -> std::shared_ptr<plugin> = 0;

	/**
	 * Search for a plugin named by this id.
	 *
	 * \param id the plugin id
	 * \return the plugin
	 * \throw plugin_error on errors
	 */
	virtual auto find(std::string_view id) -> std::shared_ptr<plugin>;
};

/**
 * \ingroup plugins
 * \brief Plugin error.
 */
class plugin_error : public std::system_error {
public:
	/**
	 * \brief Plugin related errors.
	 */
	enum error {
		//!< No error.
		no_error = 0,

		//!< The specified identifier is invalid.
		invalid_identifier,

		//!< The specified plugin is not found.
		not_found,

		//!< The plugin was unable to run the function.
		exec_error,

		//!< The plugin is already loaded.
		already_exists,
	};

private:
	std::string name_;
	std::string message_;
	std::string what_;

public:
	/**
	 * Constructor.
	 *
	 * \param code the error code
	 * \param name the plugin name
	 * \param message the optional message (e.g. error from plugin)
	 */
	plugin_error(error code, std::string_view name = "", std::string_view message = "");

	/**
	 * Get the plugin name.
	 *
	 * \return the name
	 */
	auto get_name() const noexcept -> const std::string&;

	/**
	 * Get the additional message.
	 *
	 * \return the message
	 */
	auto get_message() const noexcept -> const std::string&;

	/**
	 * Get message appropriate for use with logger.
	 *
	 * \return the error message
	 */
	auto what() const noexcept -> const char* override;
};

/**
 * Get the plugin error category singleton.
 *
 * \return the singleton
 */
auto plugin_category() -> const std::error_category&;

/**
 * Create a std::error_code from plugin_error::error enum.
 *
 * \param e the error code
 * \return the error code
 */
auto make_error_code(plugin_error::error e) -> std::error_code;

} // !irccd::daemon

/**
 * \cond IRCCD_HIDDEN_SYMBOLS
 */

namespace std {

template <>
struct is_error_code_enum<irccd::daemon::plugin_error::error> : public std::true_type {
};

} // !std

/**
 * \endcond
 */

#endif // !IRCCD_DAEMON_PLUGIN_HPP