Mercurial > irccd
changeset 126:49572a69c41d
Irccd: implement TransportService, #496
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 11 May 2016 13:00:40 +0200 |
parents | ef4bef0bf0f8 |
children | 77f950caab35 |
files | irccd/main.cpp lib/irccd/CMakeSources.cmake lib/irccd/cmd-server-cmode.cpp lib/irccd/cmd-server-cnotice.cpp lib/irccd/cmd-server-disconnect.cpp lib/irccd/cmd-server-info.cpp lib/irccd/cmd-server-invite.cpp lib/irccd/cmd-server-join.cpp lib/irccd/cmd-server-kick.cpp lib/irccd/cmd-server-list.cpp lib/irccd/cmd-server-me.cpp lib/irccd/cmd-server-message.cpp lib/irccd/cmd-server-mode.cpp lib/irccd/cmd-server-nick.cpp lib/irccd/cmd-server-notice.cpp lib/irccd/cmd-server-part.cpp lib/irccd/cmd-server-reconnect.cpp lib/irccd/cmd-server-topic.cpp lib/irccd/config.cpp lib/irccd/irccd.cpp lib/irccd/irccd.hpp lib/irccd/service-server.cpp lib/irccd/service-transport.cpp lib/irccd/service-transport.hpp |
diffstat | 24 files changed, 337 insertions(+), 243 deletions(-) [+] |
line wrap: on
line diff
--- a/irccd/main.cpp Tue May 10 22:51:10 2016 +0200 +++ b/irccd/main.cpp Wed May 11 13:00:40 2016 +0200 @@ -38,6 +38,7 @@ #include <irccd/options.hpp> #include <irccd/path.hpp> #include <irccd/service-server.hpp> +#include <irccd/service-transport.hpp> #include <irccd/system.hpp> #include <irccd/config.hpp> #include <irccd/irccd.hpp> @@ -228,7 +229,7 @@ // [transport] for (const auto &transport : config.loadTransports()) { - instance->addTransport(transport); + instance->transportService().add(transport); } // [server] section.
--- a/lib/irccd/CMakeSources.cmake Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/CMakeSources.cmake Wed May 11 13:00:40 2016 +0200 @@ -65,6 +65,7 @@ ${CMAKE_CURRENT_LIST_DIR}/service.hpp ${CMAKE_CURRENT_LIST_DIR}/service-interrupt.hpp ${CMAKE_CURRENT_LIST_DIR}/service-server.hpp + ${CMAKE_CURRENT_LIST_DIR}/service-transport.hpp ${CMAKE_CURRENT_LIST_DIR}/sockets.hpp ${CMAKE_CURRENT_LIST_DIR}/system.hpp ${CMAKE_CURRENT_LIST_DIR}/timer.hpp @@ -134,6 +135,7 @@ ${CMAKE_CURRENT_LIST_DIR}/server-state-disconnected.cpp ${CMAKE_CURRENT_LIST_DIR}/service-interrupt.cpp ${CMAKE_CURRENT_LIST_DIR}/service-server.cpp + ${CMAKE_CURRENT_LIST_DIR}/service-transport.cpp ${CMAKE_CURRENT_LIST_DIR}/sockets.cpp ${CMAKE_CURRENT_LIST_DIR}/system.cpp ${CMAKE_CURRENT_LIST_DIR}/timer.cpp
--- a/lib/irccd/cmd-server-cmode.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-cmode.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-cmode.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-cnotice.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-cnotice.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-cnotice.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-disconnect.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-disconnect.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-disconnect.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-info.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-info.cpp Wed May 11 13:00:40 2016 +0200 @@ -20,6 +20,7 @@ #include "cmd-server-info.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-invite.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-invite.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-invite.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-join.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-join.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-join.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-kick.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-kick.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-kick.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-list.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-list.cpp Wed May 11 13:00:40 2016 +0200 @@ -20,6 +20,7 @@ #include "cmd-server-list.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-me.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-me.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-me.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-message.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-message.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-message.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-mode.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-mode.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-mode.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-nick.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-nick.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-nick.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-notice.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-notice.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-notice.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-part.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-part.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-part.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-reconnect.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-reconnect.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-reconnect.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-topic.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/cmd-server-topic.cpp Wed May 11 13:00:40 2016 +0200 @@ -18,6 +18,7 @@ #include "cmd-server-topic.hpp" #include "irccd.hpp" +#include "server.hpp" #include "service-server.hpp" namespace irccd {
--- a/lib/irccd/config.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/config.cpp Wed May 11 13:00:40 2016 +0200 @@ -27,6 +27,7 @@ #include "rule.hpp" #include "server.hpp" #include "sysconfig.hpp" +#include "transport-server.hpp" #include "util.hpp" using namespace fmt::literals;
--- a/lib/irccd/irccd.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/irccd.cpp Wed May 11 13:00:40 2016 +0200 @@ -27,6 +27,7 @@ #include "path.hpp" #include "service-interrupt.hpp" #include "service-server.hpp" +#include "service-transport.hpp" #include "util.hpp" using namespace std; @@ -37,138 +38,14 @@ namespace irccd { -void Irccd::handleTransportCommand(std::weak_ptr<TransportClient> ptr, const json::Value &object) -{ - assert(object.isObject()); - - post([=] (Irccd &) { - /* 0. Be sure the object still exists */ - auto tc = ptr.lock(); - - if (!tc) { - return; - } - - /* 1. Check if the Json object is valid */ - auto name = object.find("command"); - if (name == object.end() || name->typeOf() != json::Type::String) { - // TODO: send error - log::warning("invalid command object"); - return; - } - - /* 2. Search for a command */ - auto it = m_commands.find(name->toString()); - - if (it == m_commands.end()) { - // TODO: send error again - log::warning("command does not exists"); - return; - } - - /* 3. Try to execute it */ - json::Value response = json::object({}); - - try { - response = it->second->exec(*this, object); - - /* Adjust if command has returned something else */ - if (!response.isObject()) { - response = json::object({}); - } - - response.insert("status", true); - } catch (const std::exception &ex) { - response.insert("status", false); - response.insert("error", ex.what()); - } - - /* 4. Store the command name result */ - response.insert("response", it->first); - - /* 5. Send the result */ - tc->send(response.toJson(0)); - }); -} - -void Irccd::handleTransportDie(std::weak_ptr<TransportClient> ptr) -{ - post([=] (Irccd &) { - log::info("transport: client disconnected"); - - auto tc = ptr.lock(); - - if (tc) { - m_transportClients.erase(std::find(m_transportClients.begin(), m_transportClients.end(), tc)); - } - }); -} - -void Irccd::processTransportClients(fd_set &input, fd_set &output) -{ - for (auto &client : m_transportClients) { - client->sync(input, output); - } -} - -void Irccd::processTransportServers(fd_set &input) -{ - for (auto &transport : m_transportServers) { - if (!FD_ISSET(transport->handle(), &input)) { - continue; - } - - log::debug("transport: new client connected"); - - std::shared_ptr<TransportClient> client = transport->accept(); - std::weak_ptr<TransportClient> ptr(client); - - /* Send some information */ - json::Value object = json::object({ - { "program", "irccd" }, - { "major", IRCCD_VERSION_MAJOR }, - { "minor", IRCCD_VERSION_MINOR }, - { "patch", IRCCD_VERSION_PATCH } - }); - -#if defined(WITH_JS) - object.insert("javascript", true); -#endif -#if defined(WITH_SSL) - object.insert("ssl", true); -#endif - - client->send(object.toJson(0)); - - /* Connect signals */ - client->onCommand.connect(std::bind(&Irccd::handleTransportCommand, this, ptr, _1)); - client->onDie.connect(std::bind(&Irccd::handleTransportDie, this, ptr)); - - /* Register it */ - m_transportClients.push_back(std::move(client)); - } -} - -void Irccd::process(fd_set &setinput, fd_set &setoutput) -{ - // TODO: create services for transports - for (const auto &service : m_services) { - service->sync(setinput, setoutput); - } - - /* 2. Check for transport clients */ - processTransportClients(setinput, setoutput); - - /* 3. Check for transport servers */ - processTransportServers(setinput); -} - Irccd::Irccd() : m_interruptService(std::make_shared<InterruptService>()) , m_serverService(std::make_shared<ServerService>(*this)) + , m_transportService(std::make_shared<TransportService>(*this)) { m_services.push_back(m_interruptService); m_services.push_back(m_serverService); + m_services.push_back(m_transportService); } void Irccd::post(std::function<void (Irccd &)> ev) noexcept @@ -179,19 +56,6 @@ m_interruptService->interrupt(); } -void Irccd::addTransport(std::shared_ptr<TransportServer> ts) -{ - m_transportServers.push_back(std::move(ts)); -} - -void Irccd::broadcast(std::string data) -{ - // Asynchronous send. - for (auto &client : m_transportClients) { - client->send(data); - } -} - #if defined(WITH_JS) std::shared_ptr<Plugin> Irccd::getPlugin(const std::string &name) const noexcept @@ -363,36 +227,14 @@ fd_set setoutput; net::Handle max = 0; - auto set = [&] (fd_set &set, net::Handle handle) { - FD_SET(handle, &set); - - if (handle > max) - max = handle; - }; - FD_ZERO(&setinput); FD_ZERO(&setoutput); - // TODO: create services for transports for (const auto &service : m_services) { service->prepare(setinput, setoutput, max); } - /* 3. Add transports clients */ - for (auto &client : m_transportClients) { - set(setinput, client->handle()); - - if (client->hasOutput()) { - set(setoutput, client->handle()); - } - } - - /* 4. Add transport servers */ - for (auto &transport : m_transportServers) { - set(setinput, transport->handle()); - } - - /* 5. Do the selection */ + // Do the selection. struct timeval tv; tv.tv_sec = 5; @@ -400,18 +242,21 @@ int error = select(max + 1, &setinput, &setoutput, nullptr, &tv); - /* Skip anyway */ + // Skip anyway if requested to stop if (!m_running) { return; } - /* Skip on error */ + // Skip on error. if (error < 0 && errno != EINTR) { log::warning() << "irccd: " << net::error(error) << endl; return; } - process(setinput, setoutput); + // Process after selection. + for (const auto &service : m_services) { + service->sync(setinput, setoutput); + } } void Irccd::dispatch() @@ -426,8 +271,6 @@ std::lock_guard<mutex> lock(m_mutex); copy = move(m_events); - - /* Clear for safety */ m_events.clear(); } @@ -445,6 +288,7 @@ log::debug() << "irccd: requesting to stop now" << endl; m_running = false; + m_interruptService->interrupt(); } } // !irccd
--- a/lib/irccd/irccd.hpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/irccd.hpp Wed May 11 13:00:40 2016 +0200 @@ -33,7 +33,6 @@ #include <mutex> #include <vector> -#include "sockets.hpp" #include "sysconfig.hpp" #if defined(WITH_JS) @@ -43,8 +42,6 @@ #include "application.hpp" #include "logger.hpp" #include "rule.hpp" -#include "server.hpp" -#include "transport-server.hpp" namespace irccd { @@ -53,21 +50,11 @@ class Plugin; class ServerService; class Service; -class TransportCommand; +class TransportService; /** * \class Irccd - * \brief Irccd main instance - * - * This class is used as the main application event loop, it stores servers, plugins and transports. - * - * In a general manner, no code in irccd is thread-safe because irccd is mono-threaded except the JavaScript timer - * API. - * - * If you plan to add more threads to irccd, then the simpliest and safest way to execute thread-safe code is to - * register an event using Irccd::post function which will be called during the event loop dispatching. - * - * Thus, except noticed as thread-safe, no function is assumed to be. + * \brief Irccd main instance. */ class Irccd : public Application { private: @@ -84,23 +71,13 @@ // Rules. std::vector<Rule> m_rules; - // Transports. - std::vector<std::shared_ptr<TransportClient>> m_transportClients; - std::vector<std::shared_ptr<TransportServer>> m_transportServers; - - // Services + // Services. std::shared_ptr<InterruptService> m_interruptService; std::shared_ptr<ServerService> m_serverService; + std::shared_ptr<TransportService> m_transportService; std::vector<std::shared_ptr<Service>> m_services; /* - * Transport clients slots - * ---------------------------------------------------------- - */ - void handleTransportCommand(std::weak_ptr<TransportClient>, const json::Value &); - void handleTransportDie(std::weak_ptr<TransportClient>); - - /* * Plugin timers slots * ---------------------------------------------------------- * @@ -112,17 +89,7 @@ void handleTimerEnd(std::weak_ptr<Plugin>, std::shared_ptr<Timer>); #endif - /* - * Process the socket sets. - * ---------------------------------------------------------- - * - * These functions are called after polling which sockets are ready for reading/writing. - */ - - void processTransportClients(fd_set &input, fd_set &output); - void processTransportServers(fd_set &input); - void process(fd_set &setinput, fd_set &setoutput); - + // Not copyable and not movable because services has references to irccd. Irccd(const Irccd &) = delete; Irccd(Irccd &&) = delete; @@ -137,6 +104,8 @@ /** * Add a generic service. + * + * \param service the service */ inline void addService(std::shared_ptr<Service> service) { @@ -154,6 +123,16 @@ } /** + * Access the transport service. + * + * \return the service + */ + inline TransportService &transportService() noexcept + { + return *m_transportService; + } + + /** * Add an event to the queue. This will immediately signals the event loop to interrupt itself to dispatch * the pending events. * @@ -163,27 +142,6 @@ void post(std::function<void (Irccd &)> ev) noexcept; /* - * Transport management - * ---------------------------------------------------------- - * - * Functions for adding new transport servers. - */ - - /** - * Add a transport server. - * - * \param ts the transport server - */ - void addTransport(std::shared_ptr<TransportServer> ts); - - /** - * Send data to all clients. - * - * \param data the data - */ - void broadcast(std::string data); - - /* * Plugin management * ---------------------------------------------------------- *
--- a/lib/irccd/service-server.cpp Tue May 10 22:51:10 2016 +0200 +++ b/lib/irccd/service-server.cpp Wed May 11 13:00:40 2016 +0200 @@ -22,8 +22,10 @@ #include "irccd.hpp" #include "logger.hpp" +#include "server.hpp" #include "server-event.hpp" #include "service-server.hpp" +#include "service-transport.hpp" #include "sysconfig.hpp" #include "util.hpp" @@ -45,7 +47,7 @@ log::debug() << " mode: " << mode << "\n"; log::debug() << " argument: " << arg << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onChannelMode" }, { "server", server->info().name }, { "origin", origin }, @@ -79,7 +81,7 @@ log::debug() << " channel: " << channel << "\n"; log::debug() << " message: " << message << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onChannelNotice" }, { "server", server->info().name }, { "origin", origin }, @@ -109,7 +111,7 @@ log::debug() << "server " << server->info().name << ": event onConnect" << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onConnect" }, { "server", server->info().name } }).toJson(0)); @@ -139,7 +141,7 @@ log::debug() << " channel: " << channel << "\n"; log::debug() << " target: " << target << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onInvite" }, { "server", server->info().name }, { "origin", origin }, @@ -170,7 +172,7 @@ log::debug() << " origin: " << origin << "\n"; log::debug() << " channel: " << channel << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onJoin" }, { "server", server->info().name }, { "origin", origin }, @@ -203,7 +205,7 @@ log::debug() << " target: " << target << "\n"; log::debug() << " reason: " << reason << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onKick" }, { "server", server->info().name }, { "origin", origin }, @@ -237,7 +239,7 @@ log::debug() << " channel: " << channel << "\n"; log::debug() << " message: " << message << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onMessage" }, { "server", server->info().name }, { "origin", origin }, @@ -275,7 +277,7 @@ log::debug() << " target: " << target << "\n"; log::debug() << " message: " << message << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onMe" }, { "server", server->info().name }, { "origin", origin }, @@ -307,7 +309,7 @@ log::debug() << " origin: " << origin << "\n"; log::debug() << " mode: " << mode << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onMode" }, { "server", server->info().name }, { "origin", origin }, @@ -340,7 +342,7 @@ json::Value names(std::vector<json::Value>(nicknames.begin(), nicknames.end())); - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onNames" }, { "server", server->info().name }, { "channel", channel }, @@ -371,7 +373,7 @@ log::debug() << " origin: " << origin << "\n"; log::debug() << " nickname: " << nickname << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onNick" }, { "server", server->info().name }, { "origin", origin }, @@ -402,7 +404,7 @@ log::debug() << " origin: " << origin << "\n"; log::debug() << " message: " << message << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onNotice" }, { "server", server->info().name }, { "origin", origin }, @@ -434,7 +436,7 @@ log::debug() << " channel: " << channel << "\n"; log::debug() << " reason: " << reason << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onPart" }, { "server", server->info().name }, { "origin", origin }, @@ -466,7 +468,7 @@ log::debug() << " origin: " << origin << "\n"; log::debug() << " message: " << message << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onQuery" }, { "server", server->info().name }, { "origin", origin }, @@ -503,7 +505,7 @@ log::debug() << " channel: " << channel << "\n"; log::debug() << " topic: " << topic << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "event", "onTopic" }, { "server", server->info().name }, { "origin", origin }, @@ -538,7 +540,7 @@ log::debug() << " realname: " << whois.realname << "\n"; log::debug() << " channels: " << util::join(whois.channels.begin(), whois.channels.end()) << std::endl; - m_irccd.broadcast(json::object({ + m_irccd.transportService().broadcast(json::object({ { "server", server->info().name }, { "nickname", whois.nick }, { "username", whois.user },
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/service-transport.cpp Wed May 11 13:00:40 2016 +0200 @@ -0,0 +1,181 @@ +/* + * service-transport.cpp -- manage transport servers and clients + * + * Copyright (c) 2013-2016 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. + */ + +#include "irccd.hpp" +#include "service-transport.hpp" +#include "transport-client.hpp" +#include "transport-server.hpp" + +namespace irccd { + +void TransportService::handleCommand(std::weak_ptr<TransportClient> ptr, const json::Value &object) +{ + assert(object.isObject()); + + m_irccd.post([=] (Irccd &) { + // 0. Be sure the object still exists. + auto tc = ptr.lock(); + + if (!tc) { + return; + } + + // 1. Check if the Json object is valid. + auto name = object.find("command"); + if (name == object.end() || name->typeOf() != json::Type::String) { + // TODO: send error + log::warning("invalid command object"); + return; + } + + // 2. Search for a command + auto it = m_irccd.commands().find(name->toString()); + + if (it == m_irccd.commands().end()) { + // TODO: send error again + log::warning("command does not exists"); + return; + } + + // 3. Try to execute it. + json::Value response = json::object({}); + + try { + response = it->second->exec(m_irccd, object); + + // Adjust if command has returned something else. + if (!response.isObject()) { + response = json::object({}); + } + + response.insert("status", true); + } catch (const std::exception &ex) { + response.insert("status", false); + response.insert("error", ex.what()); + } + + // 4. Store the command name result. + response.insert("response", it->first); + + // 5. Send the result. + tc->send(response.toJson(0)); + }); +} + +void TransportService::handleDie(std::weak_ptr<TransportClient> ptr) +{ + m_irccd.post([=] (Irccd &) { + log::info("transport: client disconnected"); + + auto tc = ptr.lock(); + + if (tc) { + m_clients.erase(std::find(m_clients.begin(), m_clients.end(), tc)); + } + }); +} + +TransportService::TransportService(Irccd &irccd) noexcept + : m_irccd(irccd) +{ +} + +void TransportService::prepare(fd_set &in, fd_set &out, net::Handle &max) +{ + // Add transport servers. + for (const auto &transport : m_servers) { + FD_SET(transport->handle(), &in); + + if (transport->handle() > max) { + max = transport->handle(); + } + } + + // Transport clients. + for (const auto &client : m_clients) { + FD_SET(client->handle(), &in); + + if (client->hasOutput()) { + FD_SET(client->handle(), &out); + } + if (client->handle() > max) { + max = client->handle(); + } + } +} + +void TransportService::sync(fd_set &in, fd_set &out) +{ + using namespace std::placeholders; + + // Transport servers. + for (const auto &transport : m_servers) { + if (!FD_ISSET(transport->handle(), &in)) { + continue; + } + + log::debug("transport: new client connected"); + + std::shared_ptr<TransportClient> client = transport->accept(); + std::weak_ptr<TransportClient> ptr(client); + + // Send some information. + json::Value object = json::object({ + { "program", "irccd" }, + { "major", IRCCD_VERSION_MAJOR }, + { "minor", IRCCD_VERSION_MINOR }, + { "patch", IRCCD_VERSION_PATCH } + }); + +#if defined(WITH_JS) + object.insert("javascript", true); +#endif +#if defined(WITH_SSL) + object.insert("ssl", true); +#endif + + client->send(object.toJson(0)); + + // Connect signals. + client->onCommand.connect(std::bind(&TransportService::handleCommand, this, ptr, _1)); + client->onDie.connect(std::bind(&TransportService::handleDie, this, ptr)); + + // Register it. + m_clients.push_back(std::move(client)); + } + + // Transport clients. + for (const auto &client : m_clients) { + client->sync(in, out); + } +} + +void TransportService::add(std::shared_ptr<TransportServer> ts) +{ + m_servers.push_back(std::move(ts)); +} + +void TransportService::broadcast(std::string data) +{ + // Asynchronous send. + for (const auto &client : m_clients) { + client->send(data); + } +} + +} // !irccd \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/service-transport.hpp Wed May 11 13:00:40 2016 +0200 @@ -0,0 +1,89 @@ +/* + * service-transport.hpp -- manage transport servers and clients + * + * Copyright (c) 2013-2016 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_TRANSPORT_HPP +#define IRCCD_SERVICE_TRANSPORT_HPP + +/** + * \file service-transport.hpp + * \brief manage transport servers and clients. + */ + +#include "service.hpp" + +namespace irccd { + +class TransportServer; +class TransportClient; + +namespace json { + +class Value; + +} // !json + +/** + * \brief manage transport servers and clients. + */ +class TransportService : public Service { +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 json::Value &); + void handleDie(std::weak_ptr<TransportClient>); + +public: + /** + * Create the transport service. + * + * \param irccd the irccd instance + */ + TransportService(Irccd &irccd) noexcept; + + /** + * \copydoc Service::prepare + */ + void prepare(fd_set &in, fd_set &out, net::Handle &max) override; + + /** + * \copydoc Service::sync + */ + void sync(fd_set &in, fd_set &out) override; + + /** + * Add a transport server. + * + * \param ts the transport server + */ + void add(std::shared_ptr<TransportServer> ts); + + /** + * Send data to all clients. + * + * \param data the data + */ + void broadcast(std::string data); + +}; + +} // !irccd + +#endif // !IRCCD_SERVICE_TRANSPORT_HPP \ No newline at end of file