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

          Line data    Source code
       1             : // Snap Servers -- plugins loader
       2             : // Copyright (c) 2011-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             : #include "snapwebsites/snap_exception.h"
      20             : #include "snapwebsites/snap_string_list.h"
      21             : 
      22             : #include <memory>
      23             : 
      24             : #include <QVector>
      25             : #include <QMap>
      26             : 
      27             : 
      28             : namespace snap
      29             : {
      30             : 
      31             : // bootstrap() references snap_child as a pointer
      32             : class snap_child;
      33             : 
      34             : namespace plugins
      35             : {
      36             : 
      37           0 : class plugin_exception : public snap_exception
      38             : {
      39             : public:
      40             :     explicit plugin_exception(char const *        what_msg) : snap_exception("plugin", what_msg) {}
      41           0 :     explicit plugin_exception(std::string const & what_msg) : snap_exception("plugin", what_msg) {}
      42           0 :     explicit plugin_exception(QString const &     what_msg) : snap_exception("plugin", what_msg) {}
      43             : };
      44             : 
      45             : class plugin_exception_invalid_order : public plugin_exception
      46             : {
      47             : public:
      48             :     explicit plugin_exception_invalid_order(char const *        what_msg) : plugin_exception(what_msg) {}
      49             :     explicit plugin_exception_invalid_order(std::string const & what_msg) : plugin_exception(what_msg) {}
      50             :     explicit plugin_exception_invalid_order(QString const &     what_msg) : plugin_exception(what_msg) {}
      51             : };
      52             : 
      53             : 
      54             : class plugin_signal
      55             : {
      56             : public:
      57             :     plugin_signal(const char * name);
      58             : };
      59             : 
      60             : 
      61             : 
      62             : 
      63             : class plugin
      64             : {
      65             : public:
      66             :                                         plugin();
      67             :                                         plugin(plugin const & rhs) = delete;
      68           0 :     virtual                             ~plugin() {}
      69             : 
      70             :     plugin &                            operator = (plugin const & rhs) = delete;
      71             : 
      72             :     void                                set_version(int version_major, int version_minor);
      73             :     void                                set_server_version(int version_major, int version_minor, int version_patch);
      74             :     int                                 get_major_version() const;
      75             :     int                                 get_minor_version() const;
      76             :     int                                 get_server_major_version() const;
      77             :     int                                 get_server_minor_version() const;
      78             :     int                                 get_server_patch_version() const;
      79             :     QString                             get_plugin_name() const;
      80             :     int64_t                             last_modification() const;
      81             :     virtual QString                     icon() const;
      82             :     virtual QString                     description() const = 0;
      83             :     virtual QString                     plugin_categorization_tags() const;
      84             :     virtual QString                     help_uri() const;
      85             :     virtual QString                     settings_path() const;
      86             :     virtual QString                     dependencies() const = 0;
      87             :     virtual void                        bootstrap(snap_child * snap) = 0;
      88             :     virtual int64_t                     do_update(int64_t last_updated);
      89             :     virtual int64_t                     do_dynamic_update(int64_t last_updated);
      90             : 
      91             : private:
      92             :     QString const                       f_name = QString();
      93             :     QString const                       f_filename = QString();
      94             :     mutable int64_t                     f_last_modification = 0;
      95             :     int32_t                             f_version_major = 0;
      96             :     int32_t                             f_version_minor = 0;
      97             :     int32_t                             f_server_version_major = 0;
      98             :     int32_t                             f_server_version_minor = 0;
      99             :     int32_t                             f_server_version_patch = 0;
     100             : };
     101             : 
     102             : typedef std::shared_ptr<plugin>                 plugin_ptr_t;
     103             : typedef QMap<QString, plugin *>                 plugin_map_t;
     104             : typedef QVector<plugin *>                       plugin_vector_t;
     105             : 
     106             : 
     107             : class plugin_info
     108             : {
     109             : public:
     110             :                         plugin_info(QString const & plugin_paths, QString const & name);
     111             : 
     112             :     QString const &     get_name() const;
     113             :     QString const &     get_filename() const;
     114             :     int64_t             get_last_modification() const;
     115             :     QString const &     get_icon() const;
     116             :     QString const &     get_description() const;
     117             :     QString const &     get_plugin_categorization_tags() const;
     118             :     QString const &     get_help_uri() const;
     119             :     QString const &     get_settings_path() const;
     120             :     QString const &     get_dependencies() const;
     121             :     int32_t             get_version_major() const;
     122             :     int32_t             get_version_minor() const;
     123             : 
     124             : private:
     125             :     QString             f_name = QString();
     126             :     QString             f_filename = QString();
     127             :     int64_t             f_last_modification = 0;
     128             :     QString             f_icon = QString();
     129             :     QString             f_description = QString();
     130             :     QString             f_categorization_tags = QString();
     131             :     QString             f_help_uri = QString();
     132             :     QString             f_settings_path = QString();
     133             :     QString             f_dependencies = QString();
     134             :     int32_t             f_version_major = 0;
     135             :     int32_t             f_version_minor = 0;
     136             : };
     137             : 
     138             : 
     139             : snap_string_list        list_all(QString const & plugin_path);
     140             : bool                    load(QString const & plugin_path, snap_child * snap, plugin_ptr_t server, snap_string_list const & list_of_plugins, QString const & introducer);
     141             : QString                 find_plugin_filename(snap_string_list const & plugin_paths, QString const & name);
     142             : bool                    exists(QString const & name);
     143             : void                    register_plugin(QString const & name, plugin * p);
     144             : plugin *                get_plugin(QString const & name);
     145             : plugin_map_t const &    get_plugin_list();
     146             : plugin_vector_t const & get_plugin_vector();
     147             : bool                    verify_plugin_name(QString const & name);
     148             : 
     149             : /** \brief Initialize a plugin by creating a mini-factory.
     150             :  *
     151             :  * The factory is used to create a new instance of the plugin.
     152             :  *
     153             :  * Remember that we cannot have a plugin register all of its signals
     154             :  * in its constructor. This is because many of the other plugins
     155             :  * will otherwise not already be loaded and if missing at the time
     156             :  * we try to connect, the software breaks. This is why we have the
     157             :  * bootstrap() virtual function (very much like an init() function!)
     158             :  * and this macro automatically ensures that it gets called.
     159             :  *
     160             :  * The use of the macro is very simple, it is expected to appear
     161             :  * at the beginning in your filter implementation (.cpp) file:
     162             :  *
     163             :  * \code
     164             :  * SNAP_PLUGIN_START(plugin_name, 1, 0)
     165             :  * \endcode
     166             :  *
     167             :  * Replace \<plugin_name> with the name of your plugin. The following
     168             :  * numbers represent the major and minor version numbers of the plugin.
     169             :  * They are used to show the user what he's running with. The system
     170             :  * does not otherwise do much with that information at this point.
     171             :  *
     172             :  * The name of your plugin factory is:
     173             :  *
     174             :  * \code
     175             :  * plugin_\<name>_factory
     176             :  * \endcode
     177             :  *
     178             :  * And in order to get an instance, it defines a global variable named:
     179             :  *
     180             :  * \code
     181             :  * g_plugin_\<name>_factory
     182             :  * \endcode
     183             :  *
     184             :  * The factory has a few public functions you can call:
     185             :  * \li name *instance() -- It returns a pointer to your plugin (i.e. the
     186             :  * same as 'this' in your plugin functions.)
     187             :  * \li int version_major() const -- The major version number
     188             :  * \li int version_minor() const -- The minor version number
     189             :  * \li QString version() const -- The version as a string: "<major>.<minor>"
     190             :  *
     191             :  * The constructor is automatically called when dlopen() loads
     192             :  * your plugin and the destructor is automatically called whenever
     193             :  * dl unloads the plugins.
     194             :  *
     195             :  * At the end of your implementation you have to add the
     196             :  * SNAP_PLUGIN_END() macro to close the namespaces that the start
     197             :  * macro automatically adds.
     198             :  *
     199             :  * Note that the factory initialization also takes care of
     200             :  * initializing the Qt resources of the plugin (resources
     201             :  * are mandatory in all plugins because you are expected
     202             :  * to call the add_xml() function, although a few low
     203             :  * level plugins won't do that, they still need resources.)
     204             :  *
     205             :  * \note
     206             :  * If you create multiple .cpp files to implement your plugin
     207             :  * only one can use the SNAP_PLUGIN_START()/SNAP_PLUGIN_END()
     208             :  * macros. Otherwise you'd create multiple factories. In the
     209             :  * other files, make use of the SNAP_PLUGIN_EXTENSION_START()
     210             :  * and SNAP_PLUGIN_EXTENSION_END() macros instead.
     211             :  *
     212             :  * \todo
     213             :  * Look in a way to avoid the qInitResources_... if the plugin
     214             :  * has no resources.
     215             :  *
     216             :  * \param[in] name  The name of the plugin.
     217             :  * \param[in] major  The major version of the plugin.
     218             :  * \param[in] minor  The minor version of the plugin.
     219             :  */
     220             : #define SNAP_PLUGIN_START(name, major, minor) \
     221             :     extern int qInitResources_##name(); \
     222             :     namespace snap { namespace name { \
     223             :     class plugin_##name##_factory { \
     224             :     public: plugin_##name##_factory() : f_plugin(new name()) { \
     225             :         qInitResources_##name(); \
     226             :         f_plugin->set_version(major, minor); \
     227             :         f_plugin->set_server_version(SNAPWEBSITES_VERSION_MAJOR, SNAPWEBSITES_VERSION_MINOR, SNAPWEBSITES_VERSION_PATCH); \
     228             :         ::snap::plugins::register_plugin(#name, f_plugin); } \
     229             :     virtual ~plugin_##name##_factory() { delete f_plugin; } \
     230             :     plugin_##name##_factory(plugin_##name##_factory const &) = delete; \
     231             :     plugin_##name##_factory & operator = (plugin_##name##_factory const &) = delete; \
     232             :     name * instance() { return f_plugin; } \
     233             :     virtual int version_major() const { return major; } \
     234             :     virtual int version_minor() const { return minor; } \
     235             :     virtual QString version() const { return #major "." #minor; } \
     236             :     private: name * f_plugin; \
     237             :     } g_plugin_##name##_factory;
     238             : 
     239             : 
     240             : /** \brief The counter part of the SNAP_PLUGIN_START() macro.
     241             :  *
     242             :  * This macro is used to close the namespaces opened by the
     243             :  * SNAP_PLUGIN_START() macro. It is used at the end of your
     244             :  * plugin implementation.
     245             :  */
     246             : #define SNAP_PLUGIN_END() \
     247             :     }} // close namespaces
     248             : 
     249             : 
     250             : /** \brief Initialize an extension (.cpp) file of a plugin.
     251             :  *
     252             :  * At time a plugin is really large. In order to write the plugin
     253             :  * in multiple .cpp files, you need to have a start and an end in
     254             :  * each file. Only one of the files can define the plugin factory
     255             :  * and use the SNAP_PLUGIN_START() macro. The other files want
     256             :  * to use this macro:
     257             :  *
     258             :  * \code
     259             :  * SNAP_PLUGIN_EXTENSION_START(plugin_name)
     260             :  * \endcode
     261             :  *
     262             :  * Replace \<plugin_name> with the name of your plugin. It has to
     263             :  * be the same in all the files.
     264             :  *
     265             :  * At the end of your implementation extension you have to add the
     266             :  * SNAP_PLUGIN_EXTENSION_END() macro to close the namespaces that the
     267             :  * start macro automatically adds.
     268             :  *
     269             :  * \param[in] name  The name of the plugin.
     270             :  */
     271             : #define SNAP_PLUGIN_EXTENSION_START(name) \
     272             :     namespace snap { namespace name {
     273             : 
     274             : 
     275             : /** \brief End the extension (.cpp) file of a plugin.
     276             :  *
     277             :  * When you started a .cpp file with the SNAP_PLUGIN_EXTENSION_START()
     278             :  * then you want to end it with the SNAP_PLUGIN_EXTENSION_END() macro.
     279             :  *
     280             :  * \code
     281             :  * SNAP_PLUGIN_EXTENSION_END()
     282             :  * \endcode
     283             :  */
     284             : #define SNAP_PLUGIN_EXTENSION_END() \
     285             :     }} // close namespaces
     286             : 
     287             : 
     288             : /** \brief Conditionally listen to a signal.
     289             :  *
     290             :  * This function checks whether a given plugin was loaded and if so
     291             :  * listen to one of its signals.
     292             :  *
     293             :  * The macro accepts the name of the listener plugin (it must be
     294             :  * 'this'), the name of the emitter plugin, and the name of the
     295             :  * signal to listen to.
     296             :  *
     297             :  * The listener must have a function named on_\<name of signal>.
     298             :  * The emitter is expected to define the signal using the
     299             :  * SNAP_SIGNAL() macro so the signal is called
     300             :  * signal_listen_\<name of signal>.
     301             :  *
     302             :  * \param[in] name  The name of the plugin connecting.
     303             :  * \param[in] emitter_name  The name of the plugin emitting this signal.
     304             :  * \param[in] emitter_class  The class with qualifiers if necessary of the plugin emitting this signal.
     305             :  * \param[in] signal  The name of the signal to listen to.
     306             :  * \param[in] args  The list of arguments to that signal.
     307             :  */
     308             : #define SNAP_LISTEN(name, emitter_name, emitter_class, signal, args...) \
     309             :     if(::snap::plugins::exists(emitter_name)) \
     310             :         emitter_class::instance()->signal_listen_##signal( \
     311             :                     boost::bind(&name::on_##signal, this, ##args));
     312             : 
     313             : #define SNAP_LISTEN0(name, emitter_name, emitter_class, signal) \
     314             :     if(::snap::plugins::exists(emitter_name)) \
     315             :         emitter_class::instance()->signal_listen_##signal( \
     316             :                     boost::bind(&name::on_##signal, this));
     317             : 
     318             : /** \brief Compute the number of days in the month of February.
     319             :  * \private
     320             :  *
     321             :  * The month of February is used to adjust the date by 1 day over leap
     322             :  * years. Years are leap years when multiple of 4, but not if multiple
     323             :  * of 100, except if it is also a multiple of 400.
     324             :  *
     325             :  * The computation of a leap year is documented on Wikipedia:
     326             :  * http://www.wikipedia.org/wiki/Leap_year
     327             :  *
     328             :  * \param[in] year  The year of the date to convert.
     329             :  *
     330             :  * \return 28 or 29 depending on whether the year is a leap year
     331             :  */
     332             : #define _SNAP_UNIX_TIMESTAMP_FDAY(year) \
     333             :     (((year) % 400) == 0 ? 29LL : \
     334             :         (((year) % 100) == 0 ? 28LL : \
     335             :             (((year) % 4) == 0 ? 29LL : \
     336             :                 28LL)))
     337             : 
     338             : /** \brief Compute the number of days in a year.
     339             :  * \private
     340             :  *
     341             :  * This macro returns the number of day from the beginning of the
     342             :  * year the (year, month, day) value represents.
     343             :  *
     344             :  * \param[in] year  The 4 digits year concerned.
     345             :  * \param[in] month  The month (1 to 12).
     346             :  * \param[in] day  The day of the month (1 to 31)
     347             :  *
     348             :  * \return The number of days within that year (starting at 1)
     349             :  */
     350             : #define _SNAP_UNIX_TIMESTAMP_YDAY(year, month, day) \
     351             :     ( \
     352             :         /* January */    static_cast<qint64>(day) \
     353             :         /* February */ + ((month) >=  2 ? 31LL : 0LL) \
     354             :         /* March */    + ((month) >=  3 ? _SNAP_UNIX_TIMESTAMP_FDAY(year) : 0LL) \
     355             :         /* April */    + ((month) >=  4 ? 31LL : 0LL) \
     356             :         /* May */      + ((month) >=  5 ? 30LL : 0LL) \
     357             :         /* June */     + ((month) >=  6 ? 31LL : 0LL) \
     358             :         /* July */     + ((month) >=  7 ? 30LL : 0LL) \
     359             :         /* August */   + ((month) >=  8 ? 31LL : 0LL) \
     360             :         /* September */+ ((month) >=  9 ? 31LL : 0LL) \
     361             :         /* October */  + ((month) >= 10 ? 30LL : 0LL) \
     362             :         /* November */ + ((month) >= 11 ? 31LL : 0LL) \
     363             :         /* December */ + ((month) >= 12 ? 30LL : 0LL) \
     364             :     )
     365             : 
     366             : /** \brief Compute a Unix date from a hard coded date.
     367             :  *
     368             :  * This macro is used to compute a Unix date from a date defined as 6 numbers:
     369             :  * year, month, day, hour, minute, second. Each number is expected to be an
     370             :  * integer although it could very well be an expression. The computation takes
     371             :  * the year and month in account to compute the year day which is used by
     372             :  * the do_update() functions.
     373             :  *
     374             :  * The year is expected to be written as a 4 digit number (1998, 2012, etc.)
     375             :  *
     376             :  * Each number is expected to represent a valid date. If a number is out of
     377             :  * range, then the date is still computed. It will just represent a valid
     378             :  * date, just not exactly what you wrote down.
     379             :  *
     380             :  * The math used in this macro comes from a FreeBSD implementation of mktime
     381             :  * (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15)
     382             :  *
     383             :  * \code
     384             :  * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
     385             :  *   (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
     386             :  *   ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
     387             :  * \endcode
     388             :  *
     389             :  * Note that we expect the year to be 1970 and not 0, 2000 and not 30, etc.
     390             :  * For this reason our macro subtract values from the year that are different
     391             :  * from those shown in the FreeBSD sample code.
     392             :  *
     393             :  * Also the month must be a number from 1 to 12 and not 0 to 11 as used
     394             :  * in various Unix structures.
     395             :  *
     396             :  * \param[in] year  The year representing this Unix timestamp.
     397             :  * \param[in] month  The month representing this Unix timestamp.
     398             :  * \param[in] day  The day representing this Unix timestamp.
     399             :  * \param[in] hour  The hour representing this Unix timestamp.
     400             :  * \param[in] minute  The minute representing this Unix timestamp.
     401             :  * \param[in] second  The second representing this Unix timestamp.
     402             :  */
     403             : #define SNAP_UNIX_TIMESTAMP(year, month, day, hour, minute, second) \
     404             :     ( /* time */ static_cast<qint64>(second) \
     405             :                 + static_cast<qint64>(minute) * 60LL \
     406             :                 + static_cast<qint64>(hour) * 3600LL \
     407             :     + /* year day (month + day) */ (_SNAP_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * 86400LL \
     408             :     + /* year */ (static_cast<qint64>(year) - 1970LL) * 31536000LL \
     409             :                 + ((static_cast<qint64>(year) - 1969LL) / 4LL) * 86400LL \
     410             :                 - ((static_cast<qint64>(year) - 1901LL) / 100LL) * 86400LL \
     411             :                 + ((static_cast<qint64>(year) - 1601LL) / 400LL) * 86400LL )
     412             : 
     413             : /** \brief Initialize the do_update() function.
     414             :  *
     415             :  * This macro is used to initialize the do_update() function by creating a
     416             :  * variable that is going to be given a date.
     417             :  */
     418             : #define SNAP_PLUGIN_UPDATE_INIT() int64_t last_plugin_update(SNAP_UNIX_TIMESTAMP(1990, 1, 1, 0, 0, 0) * 1000000LL);
     419             : 
     420             : /** \brief Create an update entry in your on_update() signal implementation.
     421             :  *
     422             :  * This macro is used to generate the necessary code to test the latest
     423             :  * update date and the date of the specified update.
     424             :  *
     425             :  * The function is called if the last time the website was updated it
     426             :  * was before this update. The function is then called with its own
     427             :  * date in micro-seconds (usec).
     428             :  *
     429             :  * \warning
     430             :  * The parameter to the on_update() function must be named last_updated for
     431             :  * this macro to compile as expected.
     432             :  *
     433             :  * \param[in] year  The year representing this Unix timestamp.
     434             :  * \param[in] month  The month representing this Unix timestamp.
     435             :  * \param[in] day  The day representing this Unix timestamp.
     436             :  * \param[in] hour  The hour representing this Unix timestamp.
     437             :  * \param[in] minute  The minute representing this Unix timestamp.
     438             :  * \param[in] second  The second representing this Unix timestamp.
     439             :  * \param[in] function  The name of the function to call if the update is required.
     440             :  */
     441             : #define SNAP_PLUGIN_UPDATE(year, month, day, hour, minute, second, function) \
     442             :     if(last_plugin_update > SNAP_UNIX_TIMESTAMP(year, month, day, hour, minute, second) * 1000000LL) { \
     443             :         throw plugins::plugin_exception_invalid_order("the updates in your do_update() functions must appear in increasing order in regard to date and time"); \
     444             :     } \
     445             :     last_plugin_update = SNAP_UNIX_TIMESTAMP(year, month, day, hour, minute, second) * 1000000LL; \
     446             :     if(last_updated < last_plugin_update) { \
     447             :         function(last_plugin_update); \
     448             :     }
     449             : 
     450             : /** \brief End the plugin update function.
     451             :  *
     452             :  * Use the macro as the very last line in your plugin do_update() function.
     453             :  * It returns the lastest update of your plugin.
     454             :  *
     455             :  * This function adds a return statement so anything appearing after it
     456             :  * will be ignored (not reached.)
     457             :  */
     458             : #define SNAP_PLUGIN_UPDATE_EXIT() return last_plugin_update;
     459             : 
     460             : 
     461             : } // namespace plugins
     462             : } // namespace snap
     463             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13