LCOV - code coverage report
Current view: top level - snapwebsites - snap_communicator_dispatcher.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 85 0.0 %
Date: 2019-12-15 17:13:15 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Communicator -- classes to ease handling communication between processes
       2             : // Copyright (c) 2012-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // This program is free software; you can redistribute it and/or modify
       5             : // it under the terms of the GNU General Public License as published by
       6             : // the Free Software Foundation; either version 2 of the License, or
       7             : // (at your option) any later version.
       8             : //
       9             : // This program is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             : // GNU General Public License for more details.
      13             : //
      14             : // You should have received a copy of the GNU General Public License
      15             : // along with this program; if not, write to the Free Software
      16             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             : #pragma once
      18             : 
      19             : 
      20             : // snapwebsites lib
      21             : //
      22             : #include "snapwebsites/snap_communicator.h"
      23             : #include "snapwebsites/log.h" // should be in the snap_communicator.h but can't at the moment
      24             : 
      25             : 
      26             : 
      27             : namespace snap
      28             : {
      29             : 
      30             : 
      31             : /** \brief A template to create a list of messages to dispatch on receival.
      32             :  *
      33             :  * Whenever you receive messages, they can automatically get dispatched to
      34             :  * various functions using the dispatcher.
      35             :  *
      36             :  * You define a dispatcher_match array and then add a dispatcher to
      37             :  * your connection object.
      38             :  *
      39             :  * \code
      40             :  *      snap::dispatcher<my_connection>::dispatcher_match const my_messages[] =
      41             :  *      {
      42             :  *          {
      43             :  *              "HELP"
      44             :  *            , &my_connection::msg_help
      45             :  *            //, &dispatcher<my_connection>::dispatcher_match::one_to_one_match -- use default
      46             :  *          },
      47             :  *          {
      48             :  *              "STATUS"
      49             :  *            , &my_connection::msg_status
      50             :  *            //, &dispatcher<my_connection>::dispatcher_match::one_to_one_match -- use default
      51             :  *          },
      52             :  *          ... // other messages
      53             :  *
      54             :  *          // if you'd like you can end your list with a catch all which
      55             :  *          // generate the UNKNOWN message with the following (not required)
      56             :  *          // if you have that entry, your own process_message() function
      57             :  *          // will not get called
      58             :  *          {
      59             :  *              nullptr
      60             :  *            , &dispatcher<my_connection>::dispatcher_match::msg_reply_with_unknown
      61             :  *            , &dispatcher<my_connection>::dispatcher_match::always_match
      62             :  *          },
      63             :  *      };
      64             :  * \endcode
      65             :  *
      66             :  * In most cases you do not need to specify the matching function. It will
      67             :  * use the default which is a one to one match. So in the example above,
      68             :  * for "HELP", only a message with the command set to "HELP" will match.
      69             :  * When a match is found, the correcsponding function (msg_help() here)
      70             :  * gets called.
      71             :  *
      72             :  * Note that "functions" are actually offsets. You will get `this` defined
      73             :  * as expected when your function gets called. The one drawback is that
      74             :  * only a function of the connection you attach the dispatcher to can
      75             :  * be called from the dispatcher. This is because we want to have a
      76             :  * static table instead of a dynamic one created each time we start
      77             :  * a process (in a website server, many processes get started again and
      78             :  * again.)
      79             :  *
      80             :  * \note
      81             :  * The T parameter of this template is often referenced as a "connection"
      82             :  * because it is expected to be a connection. There is actually no such
      83             :  * constraint on that object. It just needs to understand the dispatcher
      84             :  * usage which is to call the dispatch() function whenever a message is
      85             :  * received. Also it needs to implement any f_execute() function as
      86             :  * defined in its dispatch_match vector.
      87             :  *
      88             :  * \note
      89             :  * This is documented here because it is a template and we cannot do
      90             :  * that in the .cpp (at least older versions of doxygen could not.)
      91             :  */
      92             : template<typename T>
      93           0 : class dispatcher
      94             :     : public dispatcher_base
      95             : {
      96             : public:
      97             :     /** \brief A smart pointer of the dispatcher.
      98             :      *
      99             :      * Although we expect the array of `dispatcher_match` to be
     100             :      * statically defined, the `dispatcher`, on the other hand,
     101             :      * is quite dynamic and needs to be allocated in a smart
     102             :      * pointer then added to your connection.
     103             :      */
     104             :     typedef std::shared_ptr<dispatcher> pointer_t;
     105             : 
     106             :     /** \brief This structure is used to define the list of supported messages.
     107             :      *
     108             :      * Whenever you create an array of messages, you use this structure.
     109             :      *
     110             :      * The structure takes a few parameters as follow:
     111             :      *
     112             :      * \li f_expr -- the "expression" to be matched to the command name
     113             :      *               for example "HELP".
     114             :      * \li f_execute -- the function offset to execute on a match.
     115             :      * \li f_match -- the function to check whether the expression is a match;
     116             :      *                it has a default of one_to_one_match() which means the
     117             :      *                f_expr string is viewed as a plain string defining the
     118             :      *                message name as is.
     119             :      *
     120             :      * The command name is called "f_expr" but some matching functions may
     121             :      * make use of the "f_expr" parameter as an expression such as a
     122             :      * regular expression. Such functions will be added here with time, you
     123             :      * may also have your own, of course. The match function is expected to
     124             :      * be a static or standalone function.
     125             :      */
     126             :     struct dispatcher_match
     127             :     {
     128             :         /** \brief Define a vector of dispatcher_match objects.
     129             :          *
     130             :          * This function includes an array of dispatcher_match objects.
     131             :          * Whenever you define dispatcher_match objects, you want to
     132             :          * use the C++11 syntax to create a vector.
     133             :          *
     134             :          * \attention
     135             :          * We are NOT using a match because the matching may make use
     136             :          * of complex functions that support things such as complex as
     137             :          * regular expressions. In other words, the name of the message
     138             :          * may not just be a simple string.
     139             :          */
     140             :         typedef std::vector<dispatcher_match>       vector_t;
     141             : 
     142             :         /** \brief The execution function.
     143             :          *
     144             :          * This type defines the execution function. We give it the message
     145             :          * on a match. If the command name is not a match, it is ignored.
     146             :          */
     147             :         typedef void (T::*execute_func_t)(snap_communicator_message & msg);
     148             : 
     149             :         /** \brief The match function return types.
     150             :          *
     151             :          * Whenever a match function is called, it may return one of:
     152             :          *
     153             :          * \li MATCH_FALSE
     154             :          *
     155             :          * The function did not match anything. Ignore the corresponding
     156             :          * function.
     157             :          *
     158             :          * \li MATCH_TRUE
     159             :          *
     160             :          * This is a match, execute the function. We are done with this list
     161             :          * of matches.
     162             :          *
     163             :          * \li MATCH_CALLBACK
     164             :          *
     165             :          * The function is a callback, it gets called and the process
     166             :          * continues. Since the message parameter is read/write, it is
     167             :          * a way to tweak the message before other functions get it.
     168             :          */
     169             :         enum class match_t
     170             :         {
     171             :             MATCH_FALSE,
     172             :             MATCH_TRUE,
     173             :             MATCH_CALLBACK
     174             :         };
     175             : 
     176             :         /** \brief The match function.
     177             :          *
     178             :          * This type defines the match function. We give it the message
     179             :          * which has the command name, although specialized matching
     180             :          * function could test other parameters from the message such
     181             :          * as the origination of the message.
     182             :          */
     183             :         typedef match_t (*match_func_t)(QString const & expr, snap_communicator_message & msg);
     184             : 
     185             :         /** \brief The default matching function.
     186             :          *
     187             :          * This function checks the command one to one to the expression.
     188             :          * The word in the expression is compared as is to the command
     189             :          * name:
     190             :          *
     191             :          * \code
     192             :          *          return expr == msg.get_command();
     193             :          * \endcode
     194             :          *
     195             :          * We will add other matching functions with time
     196             :          * (start_with_match(), regex_match(), etc.)
     197             :          *
     198             :          * \note
     199             :          * It is permissible to use a match function to modify the
     200             :          * message in some way, however, it is not recommended.
     201             :          *
     202             :          * \param[in] expr  The expression to compare the command against.
     203             :          * \param[in] msg  The message to match against this expression.
     204             :          *
     205             :          * \return MATCH_TRUE if it is a match, MATCH_FALSE otherwise.
     206             :          */
     207           0 :         static match_t one_to_one_match(QString const & expr, snap_communicator_message & msg)
     208             :         {
     209           0 :             return expr == msg.get_command()
     210           0 :                             ? match_t::MATCH_TRUE
     211           0 :                             : match_t::MATCH_FALSE;
     212             :         }
     213             : 
     214             :         /** \brief Always returns true.
     215             :          *
     216             :          * This function always returns true. This is practical to close
     217             :          * your list of messages and return a specific message. In most
     218             :          * cases this is used to reply with the UNKNOWN message.
     219             :          *
     220             :          * \param[in] expr  The expression to compare the command against.
     221             :          * \param[in] msg  The message to match against this expression.
     222             :          *
     223             :          * \return Always returns MATCH_TRUE.
     224             :          */
     225           0 :         static match_t always_match(QString const & expr, snap_communicator_message & msg)
     226             :         {
     227           0 :             NOTUSED(expr);
     228           0 :             NOTUSED(msg);
     229           0 :             return match_t::MATCH_TRUE;
     230             :         }
     231             : 
     232             :         /** \brief Always returns true.
     233             :          *
     234             :          * This function always returns true. This is practical to close
     235             :          * your list of messages and return a specific message. In most
     236             :          * cases this is used to reply with the UNKNOWN message.
     237             :          *
     238             :          * \param[in] expr  The expression to compare the command against.
     239             :          * \param[in] msg  The message to match against this expression.
     240             :          *
     241             :          * \return Always returns MATCH_CALLBACK.
     242             :          */
     243           0 :         static match_t callback_match(QString const & expr, snap_communicator_message & msg)
     244             :         {
     245           0 :             NOTUSED(expr);
     246           0 :             NOTUSED(msg);
     247           0 :             return match_t::MATCH_CALLBACK;
     248             :         }
     249             : 
     250             :         /** \brief The expression to compare against.
     251             :          *
     252             :          * The expression is most often going to be the exact command name
     253             :          * which will be matched with the one_to_one_match() function.
     254             :          *
     255             :          * For other match functions, this would be whatever type of
     256             :          * expression supported by those other functions.
     257             :          *
     258             :          * \note
     259             :          * Effective C++ doesn't like bare pointers, but there is no real
     260             :          * reason for us to waste time and memory by having an std::string
     261             :          * here. It's going to always be a constant pointer anyway.
     262             :          */
     263             :         char const *        f_expr = nullptr;
     264             : 
     265             :         /** \brief The execute function.
     266             :          *
     267             :          * This is an offset in your connection class. We do not allow
     268             :          * std::bind() because we do not want the array of messages to be
     269             :          * dynamic (that way it is created at compile time and loaded as
     270             :          * ready/prepared data on load.)
     271             :          *
     272             :          * The functions called have `this` defined so you can access
     273             :          * your connection data and other functions. It requires the
     274             :          * `&` and the class name to define the pointer, like this:
     275             :          *
     276             :          * \code
     277             :          *      &MyClass::my_message_function
     278             :          * \endcode
     279             :          *
     280             :          * The execution is started by calling the run() function.
     281             :          */
     282             :         execute_func_t      f_execute = nullptr;
     283             : 
     284             :         /** \brief The match function.
     285             :          *
     286             :          * The match function is used to know whether that command
     287             :          * dispatch function was found.
     288             :          *
     289             :          * By default this parameter is set to one_to_one_match().
     290             :          * This means the command has to be one to one equal to
     291             :          * the f_expr string.
     292             :          *
     293             :          * The matching is done in the match() function.
     294             :          */
     295             :         match_func_t        f_match = &snap::dispatcher<T>::dispatcher_match::one_to_one_match;
     296             : 
     297             :         /** \brief Run the execution function if this is a match.
     298             :          *
     299             :          * First this function checks whether the command of the message
     300             :          * in \p msg matches this `dispatcher_match` expression. In
     301             :          * most cases the match function is going to be
     302             :          * one_on_one_match() which means it has to be exactly equal.
     303             :          *
     304             :          * If it is a match, this function runs your \p connection execution
     305             :          * function (i.e. the message gets dispatched) and then it returns
     306             :          * true.
     307             :          *
     308             :          * If the message is not a match, then the function returns false
     309             :          * and only the matching function was called. In this case the
     310             :          * \p connection does not get used.
     311             :          *
     312             :          * When this function returns true, you should not call the
     313             :          * process_message() function since that was already taken care
     314             :          * of. The process_message() function should only be called
     315             :          * if the message was not yet dispatched. When the list of
     316             :          * matches includes a catch all at the end, the process_message()
     317             :          * will never be called.
     318             :          *
     319             :          * \note
     320             :          * Note that we do not offer two functions, one to run the match
     321             :          * function and one to execute the match because you could otherwise
     322             :          * end up calling the execute function (dispatch) on any
     323             :          * `dispatcher_match` entry and we did not want that to happen.
     324             :          *
     325             :          * \param[in] connection  The connection attached to that
     326             :          *                        `dispatcher_match`.
     327             :          * \param[in] msg  The message that matched.
     328             :          *
     329             :          * \return true if the connection execute function was called.
     330             :          */
     331           0 :         bool execute(T * connection, snap::snap_communicator_message & msg) const
     332             :         {
     333           0 :             match_t m(f_match(f_expr, msg));
     334           0 :             if(m == match_t::MATCH_TRUE
     335           0 :             || m == match_t::MATCH_CALLBACK)
     336             :             {
     337           0 :                 (connection->*f_execute)(msg);
     338           0 :                 if(m == match_t::MATCH_TRUE)
     339             :                 {
     340           0 :                     return true;
     341             :                 }
     342             :             }
     343             : 
     344           0 :             return false;
     345             :         }
     346             : 
     347             :         /** \brief Check whether f_match is one_to_one_match().
     348             :          *
     349             :          * This function checks whether the f_match function was defined
     350             :          * to one_to_one_match()--the default--and if so returns true.
     351             :          *
     352             :          * \return true if f_match is the one_to_one_match() function.
     353             :          */
     354           0 :         bool match_is_one_to_one_match() const
     355             :         {
     356           0 :             return f_match == &snap::dispatcher<T>::dispatcher_match::one_to_one_match;
     357             :         }
     358             : 
     359             :         /** \brief Check whether f_match is always_match().
     360             :          *
     361             :          * This function checks whether the f_match function was defined
     362             :          * to always_match() and if so returns true.
     363             :          *
     364             :          * \return true if f_match is the always_match() function.
     365             :          */
     366           0 :         bool match_is_always_match() const
     367             :         {
     368           0 :             return f_match == &snap::dispatcher<T>::dispatcher_match::always_match;
     369             :         }
     370             : 
     371             :         /** \brief Check whether f_match is always_match().
     372             :          *
     373             :          * This function checks whether the f_match function was defined
     374             :          * to always_match() and if so returns true.
     375             :          *
     376             :          * \return true if f_match is the always_match() function.
     377             :          */
     378           0 :         bool match_is_callback_match() const
     379             :         {
     380           0 :             return f_match == &snap::dispatcher<T>::dispatcher_match::callback_match;
     381             :         }
     382             :     };
     383             : 
     384             : private:
     385             :     /** \brief The connection pointer.
     386             :      *
     387             :      * This parameter is set by the constructor. It represents the
     388             :      * connection this dispatcher was added to (a form of parent of
     389             :      * this dispatcher object.)
     390             :      */
     391             :     T *                         f_connection = nullptr;
     392             : 
     393             :     /** \brief The array of possible matches.
     394             :      *
     395             :      * This is the vector of your messages with the corresponding
     396             :      * match and execute functions. This is used to go through
     397             :      * the matches and execute (dispatch) as required.
     398             :      */
     399             :     typename snap::dispatcher<T>::dispatcher_match::vector_t  f_matches = {};
     400             : 
     401             :     /** \brief Tell whether messages should be traced or not.
     402             :      *
     403             :      * Because your service may accept and send many messages a full
     404             :      * trace on all of them can really be resource intensive. By default
     405             :      * the system will not trace anything. By setting this parameter to
     406             :      * true (call set_trace() for that) you request the SNAP_LOG_TRACE()
     407             :      * to run on each message received by this dispatcher. This is done
     408             :      * on entry so whether the message is processed by the dispatcher
     409             :      * or your own send_message() function, it will trace that message.
     410             :      */
     411             :     bool                        f_trace = false;
     412             : 
     413             : public:
     414             : 
     415             :     /** \brief Initialize the dispatcher with your connection and messages.
     416             :      *
     417             :      * This function takes a pointer to your connection and an array
     418             :      * of matches.
     419             :      *
     420             :      * Whenever a message is received by one of your connections, the
     421             :      * dispatch() function gets called which checks the message against
     422             :      * each entry in this array of \p matches.
     423             :      *
     424             :      * \param[in] connection  The connection for which this dispatcher is
     425             :      *                        created.
     426             :      * \param[in] matches  The array of dispatch keywords and functions.
     427             :      * \param[in] matches_size  The sizeof() of the matches array.
     428             :      */
     429           0 :     dispatcher<T>(T * connection, typename snap::dispatcher<T>::dispatcher_match::vector_t matches)
     430             :         : f_connection(connection)
     431           0 :         , f_matches(matches)
     432             :     {
     433           0 :     }
     434             : 
     435             :     // prevent copies
     436             :     dispatcher<T>(dispatcher<T> const & rhs) = delete;
     437             :     dispatcher<T> & operator = (dispatcher<T> const & rhs) = delete;
     438             : 
     439             :     /** \brief Add a default array of possible matches.
     440             :      *
     441             :      * In Snap! a certain number of messages are always exactly the same
     442             :      * and these can be implemented internally so each daemon doesn't have
     443             :      * to duplicate that work over and over again. These are there in part
     444             :      * because the snapcommunicator expects those messages there.
     445             :      *
     446             :      * IMPORTANT NOTE: If you add your own version in your dispatcher_match
     447             :      * vector, then these will be ignored since your version will match first
     448             :      * and the dispatcher uses the first function only.
     449             :      *
     450             :      * This array currently includes:
     451             :      *
     452             :      * \li HELP -- msg_help() -- returns the list of all the messages
     453             :      * \li LOG -- msg_log() -- reconfigure() the logger
     454             :      * \li QUITTING -- msg_quitting() -- calls stop(true);
     455             :      * \li READY -- msg_ready() -- calls ready() -- snapcommunicator always
     456             :      *              sends that message so it has to be supported
     457             :      * \li STOP -- msg_stop() -- calls stop(false);
     458             :      * \li UNKNOWN -- msg_log_unknown() -- in case we receive a message we
     459             :      *                don't understand
     460             :      * \li * -- msg_reply_with_unknown() -- the last entry will be a grab
     461             :      *          all pattern which returns the UNKNOWN message automatically
     462             :      *          for you
     463             :      *
     464             :      * The msg_...() functions must be declared in your class T. If you
     465             :      * use the system connection_with_send_message class then they're
     466             :      * already defined there.
     467             :      *
     468             :      * The HELP response is automatically built from the f_matches.f_expr
     469             :      * strings. However, if the function used to match the expression is
     470             :      * not one_to_one_match(), then that string doesn't get used.
     471             :      *
     472             :      * If any message can't be determine (i.e. the function is not the
     473             :      * one_to_one_match()) then the user help() function gets called and
     474             :      * we expect that function to add any dynamic message the daemon
     475             :      * understands.
     476             :      *
     477             :      * The LOG message reconfigures the logger if the is_configure() function
     478             :      * says it is configured. In any other circumstances, nothing happens.
     479             :      *
     480             :      * Note that the UNKNOWN message is understood and just logs the message
     481             :      * received. This allows us to see that WE sent a message that the receiver
     482             :      * (not us) does not understand and adjust our code accordingly (i.e. add
     483             :      * support for that message in that receiver or maybe fixed the spelling.)
     484             :      */
     485           0 :     void add_snap_communicator_commands()
     486             :     {
     487             :         // avoid more than one realloc()
     488             :         //
     489           0 :         f_matches.reserve(f_matches.size() + 7);
     490             : 
     491             :         {
     492           0 :             typename snap::dispatcher<T>::dispatcher_match m;
     493           0 :             m.f_expr = "HELP";
     494           0 :             m.f_execute = &T::msg_help;
     495             :             //m.f_match = <default>;
     496           0 :             f_matches.push_back(m);
     497             :         }
     498             :         {
     499           0 :             typename snap::dispatcher<T>::dispatcher_match m;
     500           0 :             m.f_expr = "ALIVE";
     501           0 :             m.f_execute = &T::msg_alive;
     502             :             //m.f_match = <default>;
     503           0 :             f_matches.push_back(m);
     504             :         }
     505             :         {
     506           0 :             typename snap::dispatcher<T>::dispatcher_match m;
     507           0 :             m.f_expr = "LOG";
     508           0 :             m.f_execute = &T::msg_log;
     509             :             //m.f_match = <default>;
     510           0 :             f_matches.push_back(m);
     511             :         }
     512             :         {
     513           0 :             typename snap::dispatcher<T>::dispatcher_match m;
     514           0 :             m.f_expr = "QUITTING";
     515           0 :             m.f_execute = &T::msg_quitting;
     516             :             //m.f_match = <default>;
     517           0 :             f_matches.push_back(m);
     518             :         }
     519             :         {
     520           0 :             typename snap::dispatcher<T>::dispatcher_match m;
     521           0 :             m.f_expr = "READY";
     522           0 :             m.f_execute = &T::msg_ready;
     523             :             //m.f_match = <default>;
     524           0 :             f_matches.push_back(m);
     525             :         }
     526             :         {
     527           0 :             typename snap::dispatcher<T>::dispatcher_match m;
     528           0 :             m.f_expr = "STOP";
     529           0 :             m.f_execute = &T::msg_stop;
     530             :             //m.f_match = <default>;
     531           0 :             f_matches.push_back(m);
     532             :         }
     533             :         {
     534           0 :             typename snap::dispatcher<T>::dispatcher_match m;
     535           0 :             m.f_expr = "UNKNOWN";
     536           0 :             m.f_execute = &T::msg_log_unknown;
     537             :             //m.f_match = <default>;
     538           0 :             f_matches.push_back(m);
     539             :         }
     540             :         {
     541           0 :             typename snap::dispatcher<T>::dispatcher_match m;
     542           0 :             m.f_expr = nullptr; // any other message
     543           0 :             m.f_execute = &T::msg_reply_with_unknown;
     544           0 :             m.f_match = &snap::dispatcher<T>::dispatcher_match::always_match;
     545           0 :             f_matches.push_back(m);
     546             :         }
     547           0 :     }
     548             : 
     549             :     typename snap::dispatcher<T>::dispatcher_match::vector_t const & get_matches() const
     550             :     {
     551             :         return f_matches;
     552             :     }
     553             : 
     554             :     /** \brief The dispatch function.
     555             :      *
     556             :      * This is the function your message system will call whenever
     557             :      * the system receives a message.
     558             :      *
     559             :      * The function returns true if the message was dispatched.
     560             :      * When that happen, the process_message() function of the
     561             :      * connection should not be called.
     562             :      *
     563             :      * You may not include a message in the array of `dispatch_match`
     564             :      * if it is too complicated to match or too many variables are
     565             :      * necessary then you will probably want to use your
     566             :      * process_message().
     567             :      *
     568             :      * By adding a catch-all at the end of your list of matches, you
     569             :      * can easily have one function called for any message. By default
     570             :      * the dispatcher environment offers such a match function and
     571             :      * it also includes a function that sends the UNKNOWN message as
     572             :      * an immediate reply to a received message.
     573             :      *
     574             :      * \param[in] msg  The message to be dispatched.
     575             :      *
     576             :      * \return true if the message was dispatched, false otherwise.
     577             :      */
     578           0 :     virtual bool dispatch(snap::snap_communicator_message & msg) override
     579             :     {
     580           0 :         if(f_trace)
     581             :         {
     582           0 :             SNAP_LOG_TRACE("dispatch message \"")
     583           0 :                           (msg.to_message())
     584             :                           ("\".");
     585             :         }
     586             : 
     587             :         // go in order to execute matches
     588             :         //
     589             :         // remember that a dispatcher with just a set of well defined command
     590             :         // names is a special case (albeit frequent) and we can't process
     591             :         // using a map (a.k.a. fast binary search) as a consequence
     592             :         //
     593           0 :         for(auto const & m : f_matches)
     594             :         {
     595           0 :             if(m.execute(f_connection, msg))
     596             :             {
     597           0 :                 return true;
     598             :             }
     599             :         }
     600             : 
     601           0 :         return false;
     602             :     }
     603             : 
     604             :     /** \brief Set whether the dispatcher should trace your messages or not.
     605             :      *
     606             :      * By default, the f_trace flag is set to false. You can change it to
     607             :      * true while debugging. You should remember to turn it back off once
     608             :      * you make an official version of your service to avoid the possibly
     609             :      * huge overhead of sending all those log messages. One way to do so
     610             :      * is to place the code within #ifdef/#endif as in:
     611             :      *
     612             :      * \code
     613             :      *     #ifdef _DEBUG
     614             :      *         my_dispatcher->set_trace();
     615             :      *     #endif
     616             :      * \endcode
     617             :      *
     618             :      * \param[in] trace  Set to true to get SNAP_LOG_TRACE() of each message.
     619             :      */
     620             :     void set_trace(bool trace = true)
     621             :     {
     622             :         f_trace = trace;
     623             :     }
     624             : 
     625             :     /** \brief Retrieve the list of commands.
     626             :      *
     627             :      * This function transforms the vector of f_matches in a list of
     628             :      * commands in a QStringList.
     629             :      *
     630             :      * \param[in,out] commands  The place where the list of commands is saved.
     631             :      *
     632             :      * \return true if the commands were all determined, false if some need
     633             :      *         help from the user of this dispatcher.
     634             :      */
     635           0 :     virtual bool get_commands(snap_string_list & commands) override
     636             :     {
     637           0 :         bool need_user_help(false);
     638           0 :         for(auto const & m : f_matches)
     639             :         {
     640           0 :             if(m.f_expr == nullptr)
     641             :             {
     642           0 :                 if(!m.match_is_always_match()
     643           0 :                 && !m.match_is_callback_match())
     644             :                 {
     645             :                     // this is a "special case" where the user has
     646             :                     // a magical function which does not require an
     647             :                     // expression at all (i.e. "hard coded" in a
     648             :                     // function)
     649             :                     //
     650           0 :                     need_user_help = true;
     651             :                 }
     652             :                 //else -- always match is the last entry and that just
     653             :                 //        means we can return UNKNOWN on an unknown message
     654             :             }
     655           0 :             else if(m.match_is_one_to_one_match())
     656             :             {
     657             :                 // add the f_expr as is since it represents a command
     658             :                 // as is
     659             :                 //
     660             :                 // note: the fromUtf8() is not extremely important
     661             :                 //       since commands have to be uppercase letters
     662             :                 //       and digits and the underscore it would work
     663             :                 //       with fromLatin1() too
     664             :                 //
     665           0 :                 commands << QString::fromUtf8(m.f_expr);
     666             :             }
     667             :             else
     668             :             {
     669             :                 // this is not a one to one match, so possibly a
     670             :                 // full regex or similar
     671             :                 //
     672           0 :                 need_user_help = true;
     673             :             }
     674             :         }
     675           0 :         return need_user_help;
     676             :     }
     677             : };
     678             : 
     679             : 
     680             : } // namespace snap
     681             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13