Mercurial > irccd
view lib/irccd/service-transport.cpp @ 207:6635b9187d71
Irccd: switch to 4 spaces indent, #518
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 21 Jun 2016 20:52:17 +0200 |
parents | b5758826f5fc |
children | 5ff2bac1c7d8 |
line wrap: on
line source
/* * 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 "command.hpp" #include "irccd.hpp" #include "json.hpp" #include "logger.hpp" #include "service-command.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 cmd = m_irccd.commandService().find(name->toString()); if (!cmd) { // TODO: send error again. log::warning("command does not exists"); return; } // 3. Try to execute it. json::Value response = json::object({}); try { response = cmd->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", name->toString()); // 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