view libirccd/irccd/service.hpp @ 464:4dd28f5416fe

Misc: update links in INSTALL.md
author David Demelier <markand@malikania.fr>
date Tue, 22 Aug 2017 16:38:05 +0200
parents acb2d4990249
children 0b156b82b8c1
line wrap: on
line source

/*
 * service.hpp -- irccd services
 *
 * 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_SERVICE_HPP
#define IRCCD_SERVICE_HPP

/**
 * \file service.hpp
 * \brief Irccd services.
 */

#include <memory>
#include <unordered_map>
#include <vector>

#include <json.hpp>

#include "command.hpp"
#include "net.hpp"
#include "plugin.hpp"
#include "rule.hpp"
#include "server.hpp"
#include "sysconfig.hpp"

namespace irccd {

/*
 * CommandService.
 * ------------------------------------------------------------------
 */

/**
 * \brief Store remote commands.
 * \ingroup services
 */
class CommandService {
private:
    std::vector<std::shared_ptr<Command>> m_commands;

public:
    /**
     * Get all commands.
     *
     * \return the list of commands.
     */
    inline const std::vector<std::shared_ptr<Command>> &commands() const noexcept
    {
        return m_commands;
    }

    /**
     * Tells if a command exists.
     *
     * \param name the command name
     * \return true if the command exists
     */
    IRCCD_EXPORT bool contains(const std::string &name) const noexcept;

    /**
     * Find a command by name.
     *
     * \param name the command name
     * \return the command or empty one if not found
     */
    IRCCD_EXPORT std::shared_ptr<Command> find(const std::string &name) const noexcept;

    /**
     * Add a command or replace existing one.
     *
     * \pre command != nullptr
     * \param command the command name
     */
    IRCCD_EXPORT void add(std::shared_ptr<Command> command);
};

/*
 * InterruptService.
 * ------------------------------------------------------------------
 */

/**
 * \brief Interrupt irccd event loop.
 * \ingroup services
 */
class InterruptService {
private:
    net::TcpSocket m_in;
    net::TcpSocket m_out;

public:
    /**
     * Prepare the socket pair.
     *
     * \throw std::runtime_error on errors
     */
    IRCCD_EXPORT InterruptService();

    /**
     * \copydoc Service::prepare
     */
    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);

    /**
     * \copydoc Service::sync
     */
    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);

    /**
     * Request interruption.
     */
    IRCCD_EXPORT void interrupt() noexcept;
};

/*
 * PluginService.
 * ------------------------------------------------------------------
 */

/**
 * \brief Manage plugins.
 * \ingroup services
 */
class PluginService {
private:
    Irccd &m_irccd;
    std::vector<std::shared_ptr<Plugin>> m_plugins;
    std::vector<std::unique_ptr<PluginLoader>> m_loaders;
    std::unordered_map<std::string, PluginConfig> m_config;
    std::unordered_map<std::string, PluginFormats> m_formats;

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

    /**
     * Destroy plugins.
     */
    IRCCD_EXPORT ~PluginService();

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

    /**
     * Check if a plugin is loaded.
     *
     * \param name the plugin id
     * \return true if has plugin
     */
    IRCCD_EXPORT 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
     */
    IRCCD_EXPORT 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
     */
    IRCCD_EXPORT 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
     */
    IRCCD_EXPORT void add(std::shared_ptr<Plugin> plugin);

    /**
     * Add a loader.
     *
     * \param loader the loader
     */
    IRCCD_EXPORT void addLoader(std::unique_ptr<PluginLoader> loader);

    /**
     * Configure a plugin.
     *
     * If the plugin is already loaded, its configuration is updated.
     *
     * \param name the plugin name
     * \param config the new configuration
     */
    IRCCD_EXPORT void setConfig(const std::string &name, PluginConfig config);

    /**
     * Get a configuration for a plugin.
     *
     * \param name the plugin name
     * \return the configuration or default one if not found
     */
    IRCCD_EXPORT PluginConfig config(const std::string &name) const;

    /**
     * Add formatting for a plugin.
     *
     * \param name the plugin name
     * \param formats the formats
     */
    IRCCD_EXPORT void setFormats(const std::string &name, PluginFormats formats);

    /**
     * Get formats for a plugin.
     *
     * \param name the plugin name
     * \return the formats
     */
    IRCCD_EXPORT PluginFormats formats(const std::string &name) const;

    /**
     * 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
     */
    IRCCD_EXPORT 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
     */
    IRCCD_EXPORT 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)
     */
    IRCCD_EXPORT void load(std::string name, std::string path = "");

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

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

/*
 * RuleService.
 * ------------------------------------------------------------------
 */

/**
 * \brief Store and solve rules.
 * \ingroup services
 */
class RuleService {
private:
    std::vector<Rule> m_rules;

public:
    /**
     * Get the list of rules.
     *
     * \return the list of rules
     */
    inline const std::vector<Rule> &list() const noexcept
    {
        return m_rules;
    }

    /**
     * Get the number of rules.
     *
     * \return the number of rules
     */
    inline std::size_t length() const noexcept
    {
        return m_rules.size();
    }

    /**
     * Append a rule.
     *
     * \param rule the rule to append
     */
    IRCCD_EXPORT void add(Rule rule);

    /**
     * Insert a new rule at the specified position.
     *
     * \param rule the rule
     * \param position the position
     */
    IRCCD_EXPORT void insert(Rule rule, unsigned position);

    /**
     * Remove a new rule from the specified position.
     *
     * \pre position must be valid
     * \param position the position
     */
    IRCCD_EXPORT void remove(unsigned position);

    /**
     * Get a rule at the specified index or throw an exception if not found.
     *
     * \param position the position
     * \return the rule
     * \throw std::out_of_range if position is invalid
     */
    IRCCD_EXPORT const Rule &require(unsigned position) const;

    /**
     * Overloaded function.
     *
     * \copydoc require
     */
    IRCCD_EXPORT Rule& require(unsigned position);

    /**
     * Resolve the action to execute with the specified list of rules.
     *
     * \param server the server name
     * \param channel the channel name
     * \param origin the origin
     * \param plugin the plugin name
     * \param event the event name (e.g onKick)
     * \return true if the plugin must be called
     */
    IRCCD_EXPORT bool solve(const std::string &server,
                            const std::string &channel,
                            const std::string &origin,
                            const std::string &plugin,
                            const std::string &event) noexcept;
};

/*
 * ServerService.
 * ------------------------------------------------------------------
 */

/**
 * \brief Manage IRC servers.
 * \ingroup services
 */
class ServerService {
private:
    Irccd &m_irccd;
    std::vector<std::shared_ptr<Server>> m_servers;

    void handleChannelMode(const ChannelModeEvent &);
    void handleChannelNotice(const ChannelNoticeEvent &);
    void handleConnect(const ConnectEvent &);
    void handleInvite(const InviteEvent &);
    void handleJoin(const JoinEvent &);
    void handleKick(const KickEvent &);
    void handleMessage(const MessageEvent &);
    void handleMe(const MeEvent &);
    void handleMode(const ModeEvent &);
    void handleNames(const NamesEvent &);
    void handleNick(const NickEvent &);
    void handleNotice(const NoticeEvent &);
    void handlePart(const PartEvent &);
    void handleQuery(const QueryEvent &);
    void handleTopic(const TopicEvent &);
    void handleWhois(const WhoisEvent &);

public:
    /**
     * Create the server service.
     */
    IRCCD_EXPORT ServerService(Irccd &instance);

    /**
     * \copydoc Service::prepare
     */
    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);

    /**
     * \copydoc Service::sync
     */
    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);

    /**
     * Get the list of servers
     *
     * \return the servers
     */
    inline const std::vector<std::shared_ptr<Server>> &servers() const noexcept
    {
        return m_servers;
    }

    /**
     * Check if a server exists.
     *
     * \param name the name
     * \return true if exists
     */
    IRCCD_EXPORT bool has(const std::string &name) const noexcept;

    /**
     * Add a new server to the application.
     *
     * \pre hasServer must return false
     * \param sv the server
     */
    IRCCD_EXPORT void add(std::shared_ptr<Server> sv);

    /**
     * Get a server or empty one if not found
     *
     * \param name the server name
     * \return the server or empty one if not found
     */
    IRCCD_EXPORT std::shared_ptr<Server> get(const std::string &name) const noexcept;

    /**
     * Find a server by name.
     *
     * \param name the server name
     * \return the server
     * \throw std::out_of_range if the server does not exist
     */
    IRCCD_EXPORT std::shared_ptr<Server> require(const std::string &name) const;

    /**
     * Remove a server from the irccd instance.
     *
     * The server if any, will be disconnected.
     *
     * \param name the server name
     */
    IRCCD_EXPORT void remove(const std::string &name);

    /**
     * Remove all servers.
     *
     * All servers will be disconnected.
     */
    IRCCD_EXPORT void clear() noexcept;
};

/*
 * TransportService.
 * ------------------------------------------------------------------
 */

class TransportServer;
class TransportClient;

/**
 * \brief manage transport servers and clients.
 * \ingroup services
 */
class TransportService {
private:
    Irccd &m_irccd;

    std::vector<std::shared_ptr<TransportServer>> m_servers;
    std::vector<std::shared_ptr<TransportClient>> m_clients;

    void handleCommand(std::weak_ptr<TransportClient>, const nlohmann::json &);
    void handleDie(std::weak_ptr<TransportClient>);

public:
    /**
     * Create the transport service.
     *
     * \param irccd the irccd instance
     */
    IRCCD_EXPORT TransportService(Irccd &irccd) noexcept;

    /**
     * \copydoc Service::prepare
     */
    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);

    /**
     * \copydoc Service::sync
     */
    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);

    /**
     * Add a transport server.
     *
     * \param ts the transport server
     */
    IRCCD_EXPORT void add(std::shared_ptr<TransportServer> ts);

    /**
     * Send data to all clients.
     *
     * \pre object.is_object()
     * \param object the json object
     */
    IRCCD_EXPORT void broadcast(const nlohmann::json &object);
};

} // !irccd

#endif // !IRCCD_SERVICE_HPP