Mercurial > irccd
view libirccd/irccd/daemon/service/transport_service.cpp @ 670:95ac3ace1610
Common: introduce new io code
To avoid code duplication in accept, connect, reading and writing we add a new
set of classes in `io` namespaces located in the following files:
- stream.hpp, acceptor.hpp, connector.hpp
These classes consist of pure abstract interfaces for I/O. Then we reimplement
them in the following files:
- socket_stream.hpp, socket_acceptor.hpp, socket_connector.hpp,
- tls_stream.hpp, tls_acceptor.hpp, tls_conncetor.hpp (for SSL).
This allows future independant connections such as DBus, fifo or any other fancy
optional stuff.
We also no longer need large class hierarchy such as `connection` for irccdctl
controller or transport_server, transport_client classes.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 10 Apr 2018 21:20:30 +0200 |
parents | 80640d2c01c5 |
children | 84c0b723100d |
line wrap: on
line source
/* * transport_service.cpp -- transport service * * Copyright (c) 2013-2018 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/sysconfig.hpp> #include <cassert> #include <irccd/json_util.hpp> #include <irccd/daemon/command.hpp> #include <irccd/daemon/irccd.hpp> #include <irccd/daemon/logger.hpp> #include <irccd/daemon/transport_util.hpp> #include <irccd/daemon/transport_client.hpp> #include "transport_service.hpp" namespace irccd { namespace { } // !namespace void transport_service::handle_command(std::shared_ptr<transport_client> tc, const nlohmann::json& object) { assert(object.is_object()); const auto name = json_util::parser(object).get<std::string>("command"); if (!name) { tc->error(irccd_error::invalid_message); return; } const auto cmd = std::find_if(commands_.begin(), commands_.end(), [&] (const auto& cptr) { return cptr->get_name() == *name; }); if (cmd == commands_.end()) tc->error(irccd_error::invalid_command, *name); else { try { (*cmd)->exec(irccd_, *tc, object); } catch (const std::system_error& ex) { tc->error(ex.code(), (*cmd)->get_name()); } catch (const std::exception& ex) { irccd_.get_log().warning() << "transport: unknown error not reported" << std::endl; irccd_.get_log().warning() << "transport: " << ex.what() << std::endl; } } } void transport_service::do_recv(std::shared_ptr<transport_client> tc) { tc->read([this, tc] (auto code, auto json) { switch (static_cast<std::errc>(code.value())) { case std::errc::not_connected: irccd_.get_log().info("transport: client disconnected"); break; case std::errc::invalid_argument: tc->error(irccd_error::invalid_message); break; default: // Other error may still happen. if (!code) { handle_command(tc, json); if (tc->get_state() == transport_client::state_t::ready) do_recv(std::move(tc)); } break; } }); } void transport_service::do_accept(transport_server& ts) { ts.accept([this, &ts] (auto code, auto client) { if (!code) { do_accept(ts); do_recv(std::move(client)); irccd_.get_log().info() << "transport: new client connected" << std::endl; } }); } transport_service::transport_service(irccd& irccd) noexcept : irccd_(irccd) { } transport_service::~transport_service() noexcept = default; void transport_service::add(std::unique_ptr<transport_server> ts) { assert(ts); do_accept(*ts); servers_.push_back(std::move(ts)); } void transport_service::broadcast(const nlohmann::json& json) { assert(json.is_object()); for (const auto& servers : servers_) for (const auto& client : servers->get_clients()) client->write(json); } void transport_service::load(const config& cfg) noexcept { for (const auto& section : cfg) { if (section.key() != "transport") continue; try { add(transport_util::from_config(irccd_.get_service(), section)); } catch (const std::exception& ex) { irccd_.get_log().warning() << "transport: " << ex.what() << std::endl; } } } } // !irccd