Mercurial > irccd
view libirccd/irccd/daemon/server_util.cpp @ 637:7632483ca971
Irccd: implement server_util, #771
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 15 Mar 2018 14:04:51 +0100 |
parents | |
children | 7e2d0739f37c |
line wrap: on
line source
/* * server_util.cpp -- server utilities * * 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 <algorithm> #include <irccd/config.hpp> #include <irccd/ini.hpp> #include <irccd/json_util.hpp> #include <irccd/string_util.hpp> #include "server_util.hpp" namespace irccd { namespace server_util { namespace { template <typename T> T to_int(const std::string& value, const std::string& name, server_error::error errc) { try { return string_util::to_int<T>(value); } catch (...) { throw server_error(errc, name); } } template <typename T> T to_uint(const std::string& value, const std::string& name, server_error::error errc) { try { return string_util::to_uint<T>(value); } catch (...) { throw server_error(errc, name); } } template <typename T> T to_uint(const nlohmann::json& value, const std::string& name, server_error::error errc) { if (!value.is_number()) throw server_error(errc, name); auto n = value.get<unsigned>(); if (n > std::numeric_limits<T>::max()) throw server_error(errc, name); return static_cast<T>(n); } std::string to_id(const ini::section& sc) { auto id = sc.get("name"); if (!string_util::is_identifier(id.value())) throw server_error(server_error::invalid_identifier, ""); return id.value(); } std::string to_id(const nlohmann::json& object) { auto id = json_util::get_string(object, "name"); if (!string_util::is_identifier(id)) throw server_error(server_error::invalid_identifier, ""); return id; } std::string to_host(const ini::section& sc, const std::string& name) { auto value = sc.get("host"); if (value.empty()) throw server_error(server_error::invalid_hostname, name); return value.value(); } std::string to_host(const nlohmann::json& object, const std::string& name) { auto value = json_util::get_string(object, "host"); if (value.empty()) throw server_error(server_error::invalid_hostname, name); return value; } void load_identity(server& server, const config& cfg, const std::string& identity) { auto sc = std::find_if(cfg.doc().begin(), cfg.doc().end(), [&] (const auto& sc) { if (sc.key() != "identity") return false; auto name = sc.find("name"); return name != sc.end() && name->value() == identity; }); if (sc == cfg.doc().end()) return; ini::section::const_iterator it; if ((it = sc->find("username")) != sc->end()) server.set_username(it->value()); if ((it = sc->find("realname")) != sc->end()) server.set_realname(it->value()); if ((it = sc->find("nickname")) != sc->end()) server.set_nickname(it->value()); if ((it = sc->find("ctcp-version")) != sc->end()) server.set_ctcp_version(it->value()); } } // !namespace std::shared_ptr<server> from_json(boost::asio::io_service& service, const nlohmann::json& object) { // TODO: move this function in server_service. auto sv = std::make_shared<server>(service, to_id(object)); // Mandatory fields. sv->set_host(to_host(object, sv->name())); // Optional fields. if (object.count("port")) sv->set_port(to_uint<std::uint16_t>(object["port"], sv->name(), server_error::invalid_port)); sv->set_password(json_util::get_string(object, "password")); sv->set_nickname(json_util::get_string(object, "nickname", sv->nickname())); sv->set_realname(json_util::get_string(object, "realname", sv->realname())); sv->set_username(json_util::get_string(object, "username", sv->username())); sv->set_ctcp_version(json_util::get_string(object, "ctcpVersion", sv->ctcp_version())); sv->set_command_char(json_util::get_string(object, "commandChar", sv->command_char())); if (json_util::get_bool(object, "ipv6")) sv->set_flags(sv->flags() | server::ipv6); if (json_util::get_bool(object, "sslVerify")) sv->set_flags(sv->flags() | server::ssl_verify); if (json_util::get_bool(object, "autoRejoin")) sv->set_flags(sv->flags() | server::auto_rejoin); if (json_util::get_bool(object, "joinInvite")) sv->set_flags(sv->flags() | server::join_invite); if (json_util::get_bool(object, "ssl")) #if defined(HAVE_SSL) sv->set_flags(sv->flags() | server::ssl); #else throw server_error(server_error::ssl_disabled, sv->name()); #endif return sv; } std::shared_ptr<server> from_config(boost::asio::io_service& service, const config& cfg, const ini::section& sc) { assert(sc.key() == "server"); auto sv = std::make_shared<server>(service, to_id(sc)); // Mandatory fields. sv->set_host(to_host(sc, sv->name())); // Optional fields. ini::section::const_iterator it; if ((it = sc.find("password")) != sc.end()) sv->set_password(it->value()); // Optional flags if ((it = sc.find("ipv6")) != sc.end() && string_util::is_boolean(it->value())) sv->set_flags(sv->flags() | server::ipv6); if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) { #if defined(HAVE_SSL) sv->set_flags(sv->flags() | server::ssl); #else throw server_error(server_error::ssl_disabled, sv->name()); #endif } if ((it = sc.find("ssl-verify")) != sc.end() && string_util::is_boolean(it->value())) sv->set_flags(sv->flags() | server::ssl_verify); // Optional identity if ((it = sc.find("identity")) != sc.end()) load_identity(*sv, cfg, it->value()); // Options if ((it = sc.find("auto-rejoin")) != sc.end() && string_util::is_boolean(it->value())) sv->set_flags(sv->flags() | server::auto_rejoin); if ((it = sc.find("join-invite")) != sc.end() && string_util::is_boolean(it->value())) sv->set_flags(sv->flags() | server::join_invite); // Channels if ((it = sc.find("channels")) != sc.end()) { for (const auto& s : *it) { channel channel; if (auto pos = s.find(":") != std::string::npos) { channel.name = s.substr(0, pos); channel.password = s.substr(pos + 1); } else channel.name = s; sv->join(channel.name, channel.password); } } if ((it = sc.find("command-char")) != sc.end()) sv->set_command_char(it->value()); // Reconnect and ping timeout if ((it = sc.find("port")) != sc.end()) sv->set_port(to_uint<std::uint16_t>(it->value(), sv->name(), server_error::invalid_port)); if ((it = sc.find("reconnect-tries")) != sc.end()) sv->set_reconnect_tries(to_int<std::int8_t>(it->value(), sv->name(), server_error::invalid_reconnect_tries)); if ((it = sc.find("reconnect-timeout")) != sc.end()) sv->set_reconnect_delay(to_uint<std::uint16_t>(it->value(), sv->name(), server_error::invalid_reconnect_timeout)); if ((it = sc.find("ping-timeout")) != sc.end()) sv->set_ping_timeout(to_uint<std::uint16_t>(it->value(), sv->name(), server_error::invalid_ping_timeout)); return sv; } } // !server_util } // !irccd