changeset 748:59029f36db60

Irccd: fix server dispatching
author David Demelier <markand@malikania.fr>
date Fri, 03 Aug 2018 12:55:00 +0200
parents 0731acfe646d
children 7851d95f2fbb
files libirccd/irccd/daemon/server.cpp libirccd/irccd/daemon/server.hpp
diffstat 2 files changed, 116 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/libirccd/irccd/daemon/server.cpp	Fri Aug 03 12:41:00 2018 +0200
+++ b/libirccd/irccd/daemon/server.cpp	Fri Aug 03 12:55:00 2018 +0200
@@ -112,16 +112,18 @@
 
 } // !namespace
 
-void server::dispatch_connect(const irc::message&, const recv_handler& handler)
+auto server::dispatch_connect(const irc::message&, const recv_handler& handler) -> bool
 {
     state_ = state::connected;
     handler({}, connect_event{shared_from_this()});
 
     for (const auto& channel : rchannels_)
         join(channel.name, channel.password);
+
+    return true;
 }
 
-void server::dispatch_endofnames(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_endofnames(const irc::message& msg, const recv_handler& handler) -> bool
 {
     /*
      * Called when end of name listing has finished on a channel.
@@ -131,21 +133,24 @@
      * params[2] == End of NAMES list
      */
     if (msg.args().size() < 3 || msg.arg(1) == "")
-        return;
+        return false;
 
     const auto it = names_map_.find(msg.arg(1));
 
     if (it != names_map_.end()) {
-        std::vector<std::string> list(it->second.begin(), it->second.end());
+        handler({}, names_event{
+            shared_from_this(),
+            msg.arg(1),
+            std::vector<std::string>(it->second.begin(), it->second.end())
+        });
 
-        handler({}, names_event{shared_from_this(), msg.arg(1), std::move(list)});
-
-        // Don't forget to remove the list.
         names_map_.erase(it);
     }
+
+    return true;
 }
 
-void server::dispatch_endofwhois(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_endofwhois(const irc::message& msg, const recv_handler& handler) -> bool
 {
     /*
      * Called when whois is finished.
@@ -158,22 +163,24 @@
 
     if (it != whois_map_.end()) {
         handler({}, whois_event{shared_from_this(), it->second});
-
-        // Don't forget to remove.
         whois_map_.erase(it);
     }
+
+    return true;
 }
 
-void server::dispatch_invite(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_invite(const irc::message& msg, const recv_handler& handler) -> bool
 {
     // If join-invite is set, join the channel.
     if ((flags_ & options::join_invite) == options::join_invite && is_self(msg.arg(0)))
         join(msg.arg(1));
 
     handler({}, invite_event{shared_from_this(), msg.prefix(), msg.arg(1), msg.arg(0)});
+
+    return true;
 }
 
-void server::dispatch_isupport(const irc::message& msg)
+auto server::dispatch_isupport(const irc::message& msg) -> bool
 {
     for (unsigned int i = 0; i < msg.args().size(); ++i) {
         if (msg.arg(i).compare(0, 6, "PREFIX") == 0) {
@@ -181,17 +188,21 @@
             break;
         }
     }
+
+    return false;
 }
 
-void server::dispatch_join(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_join(const irc::message& msg, const recv_handler& handler) -> bool
 {
     if (is_self(msg.prefix()))
         jchannels_.insert(msg.arg(0));
 
     handler({}, join_event{shared_from_this(), msg.prefix(), msg.arg(0)});
+
+    return true;
 }
 
-void server::dispatch_kick(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_kick(const irc::message& msg, const recv_handler& handler) -> bool
 {
     if (is_self(msg.arg(1))) {
         // Remove the channel from the joined list.
@@ -203,9 +214,11 @@
     }
 
     handler({}, kick_event{shared_from_this(), msg.prefix(), msg.arg(0), msg.arg(1), msg.arg(2)});
+
+    return true;
 }
 
-void server::dispatch_mode(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_mode(const irc::message& msg, const recv_handler& handler) -> bool
 {
     handler({}, mode_event{
         shared_from_this(),
@@ -216,9 +229,11 @@
         msg.arg(3),
         msg.arg(4)
     });
+
+    return true;
 }
 
-void server::dispatch_namreply(const irc::message& msg)
+auto server::dispatch_namreply(const irc::message& msg) -> bool
 {
     /*
      * Called multiple times to list clients on a channel.
@@ -232,46 +247,56 @@
      * parameter in onNames.
      */
     if (msg.args().size() < 4 || msg.arg(2) == "" || msg.arg(3) == "")
-        return;
+        return false;
 
     auto users = string_util::split(msg.arg(3), " \t");
 
     // The listing may add some prefixes, remove them if needed.
-    for (auto u : users)
+    for (const auto& u : users)
         names_map_[msg.arg(2)].insert(clean_prefix(modes_, u));
+
+    return false;
 }
 
-void server::dispatch_nick(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_nick(const irc::message& msg, const recv_handler& handler) -> bool
 {
     // Update our nickname.
     if (is_self(msg.prefix()))
         nickname_ = msg.arg(0);
 
     handler({}, nick_event{shared_from_this(), msg.prefix(), msg.arg(0)});
+
+    return true;
 }
 
-void server::dispatch_notice(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_notice(const irc::message& msg, const recv_handler& handler) -> bool
 {
     handler({}, notice_event{shared_from_this(), msg.prefix(), msg.arg(0), msg.arg(1)});
+
+    return true;
 }
 
-void server::dispatch_part(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_part(const irc::message& msg, const recv_handler& handler) -> bool
 {
     // Remove the channel from the joined list if I left a channel.
     if (is_self(msg.prefix()))
         jchannels_.erase(msg.arg(1));
 
     handler({}, part_event{shared_from_this(), msg.prefix(), msg.arg(0), msg.arg(1)});
+
+    return true;
 }
 
-void server::dispatch_ping(const irc::message& msg)
+auto server::dispatch_ping(const irc::message& msg) -> bool
 {
     assert(msg.command() == "PING");
 
     send(str(format("PONG %1%") % msg.arg(0)));
+
+    return false;
 }
 
-void server::dispatch_privmsg(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_privmsg(const irc::message& msg, const recv_handler& handler) -> bool
 {
     assert(msg.command() == "PRIVMSG");
 
@@ -280,18 +305,24 @@
 
         if (cmd.compare(0, 6, "ACTION") == 0)
             handler({}, me_event{shared_from_this(), msg.prefix(), msg.arg(0), cmd.substr(7)});
+        else
+            return false;
     } else
         handler({}, message_event{shared_from_this(), msg.prefix(), msg.arg(0), msg.arg(1)});
+
+    return true;
 }
 
-void server::dispatch_topic(const irc::message& msg, const recv_handler& handler)
+auto server::dispatch_topic(const irc::message& msg, const recv_handler& handler) -> bool
 {
     assert(msg.command() == "TOPIC");
 
     handler({}, topic_event{shared_from_this(), msg.arg(0), msg.arg(1), msg.arg(2)});
+
+    return true;
 }
 
-void server::dispatch_whoischannels(const irc::message& msg)
+auto server::dispatch_whoischannels(const irc::message& msg) -> bool
 {
     /*
      * Called when we have received channels for one user.
@@ -301,7 +332,7 @@
      * params[2] == list of channels with their prefixes
      */
     if (msg.args().size() < 3 || msg.arg(1) == "" || msg.arg(2) == "")
-        return;
+        return false;
 
     auto it = whois_map_.find(msg.arg(1));
 
@@ -314,9 +345,11 @@
 
         it->second.channels = std::move(channels);
     }
+
+    return false;
 }
 
-void server::dispatch_whoisuser(const irc::message& msg)
+auto server::dispatch_whoisuser(const irc::message& msg) -> bool
 {
     /*
      * Called when whois information has been partially received.
@@ -329,7 +362,7 @@
      * params[5] == realname
      */
     if (msg.args().size() < 6 || msg.arg(1) == "" || msg.arg(2) == "" || msg.arg(3) == "" || msg.arg(5) == "")
-        return;
+        return false;
 
     whois_info info;
 
@@ -339,44 +372,50 @@
     info.realname = msg.arg(5);
 
     whois_map_.emplace(info.nick, info);
+
+    return false;
 }
 
-void server::dispatch(const irc::message& message, const recv_handler& handler)
+auto server::dispatch(const irc::message& message, const recv_handler& handler) -> bool
 {
+    bool handled = false;
+
     if (message.is(5))
-        dispatch_isupport(message);
+        handled = dispatch_isupport(message);
     else if (message.is(irc::err::nomotd) || message.is(irc::rpl::endofmotd))
-        dispatch_connect(message, handler);
+        handled = dispatch_connect(message, handler);
     else if (message.command() == "INVITE")
-        dispatch_invite(message, handler);
+        handled = dispatch_invite(message, handler);
     else if (message.command() == "JOIN")
-        dispatch_join(message, handler);
+        handled = dispatch_join(message, handler);
     else if (message.command() == "KICK")
-        dispatch_kick(message, handler);
+        handled = dispatch_kick(message, handler);
     else if (message.command() == "MODE")
-        dispatch_mode(message, handler);
+        handled = dispatch_mode(message, handler);
     else if (message.command() == "NICK")
-        dispatch_nick(message, handler);
+        handled = dispatch_nick(message, handler);
     else if (message.command() == "NOTICE")
-        dispatch_notice(message, handler);
+        handled = dispatch_notice(message, handler);
     else if (message.command() == "TOPIC")
-        dispatch_topic(message, handler);
+        handled = dispatch_topic(message, handler);
     else if (message.command() == "PART")
-        dispatch_part(message, handler);
+        handled = dispatch_part(message, handler);
     else if (message.command() == "PING")
-        dispatch_ping(message);
+        handled = dispatch_ping(message);
     else if (message.command() == "PRIVMSG")
-        dispatch_privmsg(message, handler);
+        handled = dispatch_privmsg(message, handler);
     else if (message.is(irc::rpl::namreply))
-        dispatch_namreply(message);
+        handled = dispatch_namreply(message);
     else if (message.is(irc::rpl::endofnames))
-        dispatch_endofnames(message, handler);
+        handled = dispatch_endofnames(message, handler);
     else if (message.is(irc::rpl::endofwhois))
-        dispatch_endofwhois(message, handler);
+        handled = dispatch_endofwhois(message, handler);
     else if (message.is(irc::rpl::whoischannels))
-        dispatch_whoischannels(message);
+        handled = dispatch_whoischannels(message);
     else if (message.is(irc::rpl::whoisuser))
-        dispatch_whoisuser(message);
+        handled = dispatch_whoisuser(message);
+
+    return handled;
 }
 
 void server::handle_send(const std::error_code& code)
@@ -395,11 +434,17 @@
                          const irc::message& message,
                          const recv_handler& handler)
 {
+    /*
+     * Once a message is received, dispatch it to individual dispatch_*
+     * functions. If the function calls handler by itself it returns true
+     * otherwise we call handler with no event to tell the caller the message
+     * has arrived and allowed to call recv() again.
+     */
     if (code) {
         disconnect();
         handler(std::move(code), event(std::monostate()));
-    } else
-        dispatch(message, handler);
+    } else if (!dispatch(message, handler))
+        handler({}, std::monostate{});
 }
 
 void server::recv(recv_handler handler) noexcept
@@ -411,7 +456,7 @@
 
 void server::flush()
 {
-    if (queue_.empty() || state_ != state::connected)
+    if (queue_.empty())
         return;
 
     const auto self = shared_from_this();
@@ -442,11 +487,12 @@
 {
     timer_.cancel();
 
-    if (code) {
+    if (code)
         disconnect();
-        handler(code);
-    } else
+    else
         identify();
+
+    handler(code);
 }
 
 server::server(boost::asio::io_service& service, std::string id, std::string host)
--- a/libirccd/irccd/daemon/server.hpp	Fri Aug 03 12:41:00 2018 +0200
+++ b/libirccd/irccd/daemon/server.hpp	Fri Aug 03 12:55:00 2018 +0200
@@ -307,24 +307,24 @@
     std::map<std::string, std::set<std::string>> names_map_;
     std::map<std::string, whois_info> whois_map_;
 
-    void dispatch_connect(const irc::message&, const recv_handler&);
-    void dispatch_endofnames(const irc::message&, const recv_handler&);
-    void dispatch_endofwhois(const irc::message&, const recv_handler&);
-    void dispatch_invite(const irc::message&, const recv_handler&);
-    void dispatch_isupport(const irc::message&);
-    void dispatch_join(const irc::message&, const recv_handler&);
-    void dispatch_kick(const irc::message&, const recv_handler&);
-    void dispatch_mode(const irc::message&, const recv_handler&);
-    void dispatch_namreply(const irc::message&);
-    void dispatch_nick(const irc::message&, const recv_handler&);
-    void dispatch_notice(const irc::message&, const recv_handler&);
-    void dispatch_part(const irc::message&, const recv_handler&);
-    void dispatch_ping(const irc::message&);
-    void dispatch_privmsg(const irc::message&, const recv_handler&);
-    void dispatch_topic(const irc::message&, const recv_handler&);
-    void dispatch_whoischannels(const irc::message&);
-    void dispatch_whoisuser(const irc::message&);
-    void dispatch(const irc::message&, const recv_handler&);
+    auto dispatch_connect(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_endofnames(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_endofwhois(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_invite(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_isupport(const irc::message&) -> bool;
+    auto dispatch_join(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_kick(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_mode(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_namreply(const irc::message&) -> bool;
+    auto dispatch_nick(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_notice(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_part(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_ping(const irc::message&) -> bool;
+    auto dispatch_privmsg(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_topic(const irc::message&, const recv_handler&) -> bool;
+    auto dispatch_whoischannels(const irc::message&) -> bool;
+    auto dispatch_whoisuser(const irc::message&) -> bool;
+    auto dispatch(const irc::message&, const recv_handler&) -> bool;
 
     // I/O and connection.
     void flush();