From aad06fdc3a6c6aa09c647b6be7cd970542471d2f Mon Sep 17 00:00:00 2001 From: antao Date: Fri, 29 Mar 2019 15:34:14 +0800 Subject: [PATCH] Add support for plugins --- CMakeLists.txt | 3 + config.example.json | 13 +++ drogon_ctl/create.cc | 2 + drogon_ctl/create_filter.cc | 2 +- drogon_ctl/create_plugin.cc | 107 ++++++++++++++++++++ drogon_ctl/create_plugin.h | 31 ++++++ drogon_ctl/create_project.cc | 1 + drogon_ctl/templates/cmake.csp | 3 +- drogon_ctl/templates/config.csp | 13 +++ drogon_ctl/templates/plugin_cc.csp | 23 +++++ drogon_ctl/templates/plugin_h.csp | 36 +++++++ examples/simple_example/DoNothingPlugin.cc | 19 ++++ examples/simple_example/DoNothingPlugin.h | 25 +++++ examples/simple_example/TestPlugin.cc | 32 ++++++ examples/simple_example/TestPlugin.h | 28 ++++++ lib/inc/drogon/HttpAppFramework.h | 27 +++++ lib/inc/drogon/plugins/Plugin.h | 109 +++++++++++++++++++++ lib/src/HttpAppFrameworkImpl.cc | 13 ++- lib/src/HttpAppFrameworkImpl.h | 14 ++- lib/src/PluginsManager.cc | 100 +++++++++++++++++++ lib/src/PluginsManager.h | 38 +++++++ 21 files changed, 633 insertions(+), 6 deletions(-) create mode 100644 drogon_ctl/create_plugin.cc create mode 100644 drogon_ctl/create_plugin.h create mode 100644 drogon_ctl/templates/plugin_cc.csp create mode 100644 drogon_ctl/templates/plugin_h.csp create mode 100644 examples/simple_example/DoNothingPlugin.cc create mode 100644 examples/simple_example/DoNothingPlugin.h create mode 100644 examples/simple_example/TestPlugin.cc create mode 100644 examples/simple_example/TestPlugin.h create mode 100644 lib/inc/drogon/plugins/Plugin.h create mode 100644 lib/src/PluginsManager.cc create mode 100644 lib/src/PluginsManager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fd4b4e30..ce5cbe2c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -214,5 +214,8 @@ endif() file(GLOB drogon_util_headers "${CMAKE_CURRENT_SOURCE_DIR}/lib/inc/drogon/utils/*.h") install(FILES ${drogon_util_headers} DESTINATION include/drogon/utils) +file(GLOB drogon_plugin_headers "${CMAKE_CURRENT_SOURCE_DIR}/lib/inc/drogon/plugins/*.h") +install(FILES ${drogon_plugin_headers} + DESTINATION include/drogon/plugins) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/lib/inc/drogon/version.h" DESTINATION include/drogon) diff --git a/config.example.json b/config.example.json index 45cd95a9..7245447f 100644 --- a/config.example.json +++ b/config.example.json @@ -149,6 +149,19 @@ //The default value of 0 means no limit. "pipeline_requests": 0 }, + //plugins: Define all plugins running in the application + "plugins": [{ + //name: The class name of the plugin + //"name": "TestPlugin", + //dependencies: Plugins that the plugin depends on. It can be commented out + "dependencies": [], + //config: The configuration of the plugin. This json object is the parameter to initialize the plugin. + //It can be commented out + "config": { + "heartbeat_interval": 2 + } + + }], //custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method. "custom_config": {} } \ No newline at end of file diff --git a/drogon_ctl/create.cc b/drogon_ctl/create.cc index e601efc0..1afdea28 100755 --- a/drogon_ctl/create.cc +++ b/drogon_ctl/create.cc @@ -31,6 +31,8 @@ std::string create::detail() "create WebSocketController source files\n\n" "drogon_ctl create filter <[namespace::]class_name> //" "create a filter named class_name\n\n" + "drogon_ctl create plugin <[namespace::]class_name> //" + "create a plugin named class_name\n\n" "drogon_ctl create project //" "create a project named project_name\n\n" "drogon_ctl create model //" diff --git a/drogon_ctl/create_filter.cc b/drogon_ctl/create_filter.cc index 15af1daa..10585032 100644 --- a/drogon_ctl/create_filter.cc +++ b/drogon_ctl/create_filter.cc @@ -100,7 +100,7 @@ void create_filter::handleCommand(std::vector ¶meters) exit(-1); } - std::cout << "create a http fitler:" << className << std::endl; + std::cout << "create a http filter:" << className << std::endl; createFilterHeaderFile(oHeadFile, className, fileName); createFilterSourceFile(oSourceFile, className, fileName); } diff --git a/drogon_ctl/create_plugin.cc b/drogon_ctl/create_plugin.cc new file mode 100644 index 00000000..d68a3454 --- /dev/null +++ b/drogon_ctl/create_plugin.cc @@ -0,0 +1,107 @@ +/** + * + * create_plugin.cc + * An Tao + * + * Copyright 2018, An Tao. All rights reserved. + * https://github.com/an-tao/drogon + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Drogon + * + */ + +#include "create_plugin.h" +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace drogon_ctl; + +static void createPluginHeaderFile(std::ofstream &file, const std::string &className, const std::string &fileName) +{ + auto templ = drogon::DrTemplateBase::newTemplate("plugin_h"); + HttpViewData data; + if (className.find("::") != std::string::npos) + { + auto namespaceVector = utils::splitString(className, "::"); + data.insert("className", namespaceVector.back()); + namespaceVector.pop_back(); + data.insert("namespaceVector", namespaceVector); + } + else + { + data.insert("className", className); + } + data.insert("filename", fileName); + file << templ->genText(data); +} + +static void createPluginSourceFile(std::ofstream &file, const std::string &className, const std::string &fileName) +{ + auto templ = drogon::DrTemplateBase::newTemplate("plugin_cc"); + HttpViewData data; + if (className.find("::") != std::string::npos) + { + auto pos = className.rfind("::"); + data.insert("namespaceString", className.substr(0, pos)); + data.insert("className", className.substr(pos + 2)); + } + else + { + data.insert("className", className); + } + data.insert("filename", fileName); + file << templ->genText(data); +} +void create_plugin::handleCommand(std::vector ¶meters) +{ + if (parameters.size() < 1) + { + std::cout << "Invalid parameters!" << std::endl; + } + for (auto className : parameters) + { + std::regex regex("::"); + std::string fileName = std::regex_replace(className, regex, std::string("_")); + + std::string headFileName = fileName + ".h"; + std::string sourceFilename = fileName + ".cc"; + { + std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in); + std::ifstream iSourceFile(sourceFilename.c_str(), std::ifstream::in); + + if (iHeadFile || iSourceFile) + { + std::cout << "The file you want to create already exists, overwrite it(y/n)?" << std::endl; + auto in = getchar(); + (void)getchar(); //get the return key + if (in != 'Y' && in != 'y') + { + std::cout << "Abort!" << std::endl; + exit(0); + } + } + } + std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out); + std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out); + if (!oHeadFile || !oSourceFile) + { + perror(""); + exit(-1); + } + + std::cout << "create a plugin:" << className << std::endl; + createPluginHeaderFile(oHeadFile, className, fileName); + createPluginSourceFile(oSourceFile, className, fileName); + } +} diff --git a/drogon_ctl/create_plugin.h b/drogon_ctl/create_plugin.h new file mode 100644 index 00000000..e39652a6 --- /dev/null +++ b/drogon_ctl/create_plugin.h @@ -0,0 +1,31 @@ +/** + * + * create_plugin.h + * An Tao + * + * Copyright 2018, An Tao. All rights reserved. + * https://github.com/an-tao/drogon + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Drogon + * + */ + +#pragma once + +#include +#include "CommandHandler.h" +using namespace drogon; +namespace drogon_ctl +{ +class create_plugin : public DrObject, public CommandHandler +{ + public: + virtual void handleCommand(std::vector ¶meters) override; + virtual std::string script() override { return "create plugin class files"; } + + protected: + std::string _outputPath = "."; +}; +} // namespace drogon_ctl diff --git a/drogon_ctl/create_project.cc b/drogon_ctl/create_project.cc index 2c2aa3e8..e7e8a66a 100644 --- a/drogon_ctl/create_project.cc +++ b/drogon_ctl/create_project.cc @@ -104,6 +104,7 @@ void create_project::createProject(const std::string &projectName) mkdir("views", 0755); mkdir("controllers", 0755); mkdir("filters", 0755); + mkdir("plugins", 0755); mkdir("build", 0755); mkdir("models", 0755); mkdir("cmake_modules", 0755); diff --git a/drogon_ctl/templates/cmake.csp b/drogon_ctl/templates/cmake.csp index 3db6a59a..2fd1f99a 100644 --- a/drogon_ctl/templates/cmake.csp +++ b/drogon_ctl/templates/cmake.csp @@ -84,6 +84,7 @@ endif() AUX_SOURCE_DIRECTORY(./ SRC_DIR) AUX_SOURCE_DIRECTORY(controllers CTL_SRC) AUX_SOURCE_DIRECTORY(filters FILTER_SRC) +AUX_SOURCE_DIRECTORY(plugins PLUGIN_SRC) AUX_SOURCE_DIRECTORY(models MODEL_SRC) include_directories(/usr/local/include) @@ -102,4 +103,4 @@ foreach(cspFile ${SCP_LIST}) endforeach() include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -add_executable({{ProjectName}} ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${MODEL_SRC}) +add_executable({{ProjectName}} ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${PLUGIN_SRC} ${MODEL_SRC}) diff --git a/drogon_ctl/templates/config.csp b/drogon_ctl/templates/config.csp index 45cd95a9..729dab70 100644 --- a/drogon_ctl/templates/config.csp +++ b/drogon_ctl/templates/config.csp @@ -149,6 +149,19 @@ //The default value of 0 means no limit. "pipeline_requests": 0 }, + //plugins: Define all plugins running in the application + "plugins": [{ + //name: The class name of the plugin + //"name": "TestPlugin", + //dependencies: Plugins that the plugin depends on. It's a null object by default. + "dependencies": [], + //config: The configuration of the plugin. This json object is the parameter to initialize the plugin. + //It's a null object by default. + "config": { + "heartbeat_interval": 2 + } + + }], //custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method. "custom_config": {} } \ No newline at end of file diff --git a/drogon_ctl/templates/plugin_cc.csp b/drogon_ctl/templates/plugin_cc.csp new file mode 100644 index 00000000..f7c9ab1f --- /dev/null +++ b/drogon_ctl/templates/plugin_cc.csp @@ -0,0 +1,23 @@ +/** + * + * {{filename}}.cc + * + */ + +#include "{{filename}}.h" + +using namespace drogon; +<%c++auto namespaceStr=@@.get("namespaceString"); +if(!namespaceStr.empty()) +$$<<"using namespace "< + +void {{className}}::initAndStart(const Json::Value &config) +{ + /// Initialize and start the plugin +} + +void {{className}}::shutdown() +{ + /// Shutdown the plugin +} diff --git a/drogon_ctl/templates/plugin_h.csp b/drogon_ctl/templates/plugin_h.csp new file mode 100644 index 00000000..33813cd0 --- /dev/null +++ b/drogon_ctl/templates/plugin_h.csp @@ -0,0 +1,36 @@ +/** + * + * {{filename}}.h + * + */ + +#pragma once + +#include +using namespace drogon; +<%c++ +auto namespaceVector=@@.get>("namespaceVector"); +if(namespaceVector.empty()) +$$<<"\n"; +for(auto &namespaceName:namespaceVector){%> +namespace {%namespaceName%} + +{ +<%c++} +$$<<"\n";%> +class {{className}} : public Plugin<{{className}}> +{ + public: + {{className}}() {} + /// This method must be called by drogon to initialize and start the plugin. + /// It must be implemented by the user. + virtual void initAndStart(const Json::Value &config) override; + + /// This method must be called by drogon to shutdown the plugin. + /// It must be implemented by the user. + virtual void shutdown() override; +}; + +<%c++for(size_t i=0;i +} +<%c++}%> \ No newline at end of file diff --git a/examples/simple_example/DoNothingPlugin.cc b/examples/simple_example/DoNothingPlugin.cc new file mode 100644 index 00000000..2f236ac9 --- /dev/null +++ b/examples/simple_example/DoNothingPlugin.cc @@ -0,0 +1,19 @@ +/** + * + * DoNothingPlugin.cc + * + */ + +#include "DoNothingPlugin.h" + +using namespace drogon; + +void DoNothingPlugin::initAndStart(const Json::Value &config) +{ + /// Initialize and start the plugin +} + +void DoNothingPlugin::shutdown() +{ + /// Shutdown the plugin +} diff --git a/examples/simple_example/DoNothingPlugin.h b/examples/simple_example/DoNothingPlugin.h new file mode 100644 index 00000000..a0070ae2 --- /dev/null +++ b/examples/simple_example/DoNothingPlugin.h @@ -0,0 +1,25 @@ +/** + * + * DoNothingPlugin.h + * + */ + +#pragma once + +#include +using namespace drogon; + + +class DoNothingPlugin : public Plugin +{ + public: + DoNothingPlugin() {} + /// This method must be called by drogon to initialize and start the plugin. + /// It must be implemented by the user. + virtual void initAndStart(const Json::Value &config) override; + + /// This method must be called by drogon to shutdown the plugin. + /// It must be implemented by the user. + virtual void shutdown() override; +}; + diff --git a/examples/simple_example/TestPlugin.cc b/examples/simple_example/TestPlugin.cc new file mode 100644 index 00000000..85b8bc98 --- /dev/null +++ b/examples/simple_example/TestPlugin.cc @@ -0,0 +1,32 @@ +/** + * + * TestPlugin.cc + * + */ + +#include "TestPlugin.h" +#include + +using namespace drogon; + +void TestPlugin::initAndStart(const Json::Value &config) +{ + /// Initialize and start the plugin + if(config.isNull()) + LOG_DEBUG << "Configuration not defined"; + _interval = config.get("heartbeat_interval", 1).asInt(); + _workThread = std::thread([this]() { + while(!_stop) + { + LOG_DEBUG << "TestPlugin heartbeat!"; + sleep(_interval); + } + }); +} + +void TestPlugin::shutdown() +{ + /// Shutdown the plugin + _stop = true; + _workThread.join(); +} diff --git a/examples/simple_example/TestPlugin.h b/examples/simple_example/TestPlugin.h new file mode 100644 index 00000000..c946aa7d --- /dev/null +++ b/examples/simple_example/TestPlugin.h @@ -0,0 +1,28 @@ +/** + * + * TestPlugin.h + * + */ + +#pragma once + +#include +using namespace drogon; + +class TestPlugin : public Plugin +{ + public: + TestPlugin() {} + /// This method must be called by drogon to initialize and start the plugin. + /// It must be implemented by the user. + virtual void initAndStart(const Json::Value &config) override; + + /// This method must be called by drogon to shutdown the plugin. + /// It must be implemented by the user. + virtual void shutdown() override; + + private: + std::thread _workThread; + bool _stop = false; + int _interval; +}; diff --git a/lib/inc/drogon/HttpAppFramework.h b/lib/inc/drogon/HttpAppFramework.h index 95ae6428..f7a1358b 100755 --- a/lib/inc/drogon/HttpAppFramework.h +++ b/lib/inc/drogon/HttpAppFramework.h @@ -31,12 +31,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include + namespace drogon { //the drogon banner @@ -101,6 +104,30 @@ class HttpAppFramework : public trantor::NonCopyable */ virtual trantor::EventLoop *getLoop() = 0; + ///Get the plugin object registered in the framework + /** + * NOTE: + * This method is usually called after the framework is run. + * Calling this method in the initAndStart() method of some plugins is also valid. + */ + template + T *getPlugin() + { + static_assert(IsPlugin::value, "The Template parameter must be a subclass of PluginBase"); + assert(isRunning()); + return dynamic_cast(getPlugin(T::className())); + } + + ///Get the plugin object registered in the framework + /** + * @param name: is the class name of the plugin. + * + * NOTE: + * This method is usually called after the framework is run. + * Calling this method in the initAndStart() method of some plugins is also valid. + */ + virtual PluginBase *getPlugin(const std::string &name) = 0; + ///Load the configuration file with json format. virtual void loadConfigFile(const std::string &fileName) = 0; diff --git a/lib/inc/drogon/plugins/Plugin.h b/lib/inc/drogon/plugins/Plugin.h new file mode 100644 index 00000000..e1fa424a --- /dev/null +++ b/lib/inc/drogon/plugins/Plugin.h @@ -0,0 +1,109 @@ +/** + * Plugin.h + * An Tao + * + * Copyright 2018, An Tao. All rights reserved. + * https://github.com/an-tao/drogon + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Drogon + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace drogon +{ + +enum class PluginState +{ + None, + Initializing, + Initialized +}; + +class PluginBase : public virtual DrObjectBase, public trantor::NonCopyable +{ + public: + /// This method is usually called by drogon. + /// it always returns PlugiinState::Initialized if the user calls it. + PluginState stat() const { return _stat; } + + /// This method must be called by drogon. + void initialize() + { + if (_stat == PluginState::None) + { + _stat = PluginState::Initializing; + for (auto dependency : _dependencies) + { + dependency->initialize(); + } + initAndStart(_config); + _stat = PluginState::Initialized; + if (_initializedCallback) + _initializedCallback(this); + } + else if (_stat == PluginState::Initialized) + { + //Do nothing; + } + else + { + LOG_FATAL << "There are a loop-dependency within plugins."; + abort(); + } + } + + /// This method must be called by drogon to initialize and start the plugin. + /// It must be implemented by the user. + virtual void initAndStart(const Json::Value &config) = 0; + + /// This method must be called by drogon to shutdown the plugin. + /// It must be implemented by the user. + virtual void shutdown() = 0; + + virtual ~PluginBase() {} + + protected: + PluginBase() {} + + private: + PluginState _stat = PluginState::None; + friend class PluginsManager; + void setConfig(const Json::Value &config) { _config = config; } + void addDependency(PluginBase *dp) { _dependencies.push_back(dp); } + void setInitializedCallback(const std::function &cb) { _initializedCallback = cb; } + Json::Value _config; + std::vector _dependencies; + std::function _initializedCallback; +}; + +template +struct IsPlugin +{ + typedef typename std::remove_cv::type>::type TYPE; + + static int test(void *p) { return 0; } + static char test(PluginBase *p) { return 0; } + static constexpr bool value = (sizeof(test((TYPE *)nullptr)) == sizeof(int)); +}; + +template +class Plugin : public PluginBase, public DrObject +{ + public: + virtual ~Plugin() {} + + protected: + Plugin() {} +}; + +} // namespace drogon \ No newline at end of file diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index 6af8fa7f..b04c74de 100755 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -157,8 +157,7 @@ void HttpAppFrameworkImpl::loadConfigFile(const std::string &fileName) { ConfigLoader loader(fileName); loader.load(); - auto &jsonRoot = loader.jsonValue(); - _customConfig = jsonRoot.get("custom_config", Json::Value()); + _jsonConfig = loader.jsonValue(); } void HttpAppFrameworkImpl::setLogPath(const std::string &logPath, const std::string &logfileBaseName, @@ -415,6 +414,16 @@ void HttpAppFrameworkImpl::run() } _responseCachingMap = std::unique_ptr>(new CacheMap(getLoop(), 1.0, 4, 50)); //Max timeout up to about 70 days; + //Initialize plugins + const auto &pluginConfig = _jsonConfig["plugins"]; + if (!pluginConfig.isNull()) + { + _pluginsManager.initializeAllPlugins(pluginConfig, + [](PluginBase *plugin) { + //TODO: new plugin + }); + } + // Let listener event loops run when everything is ready. for (auto &loopTh : loopThreads) { diff --git a/lib/src/HttpAppFrameworkImpl.h b/lib/src/HttpAppFrameworkImpl.h index d280cf6d..78688646 100644 --- a/lib/src/HttpAppFrameworkImpl.h +++ b/lib/src/HttpAppFrameworkImpl.h @@ -22,6 +22,7 @@ #include "HttpControllersRouter.h" #include "HttpSimpleControllersRouter.h" #include "WebsocketControllersRouter.h" +#include "PluginsManager.h" #include #include @@ -53,10 +54,17 @@ class HttpAppFrameworkImpl : public HttpAppFramework _connectionNum(0) { } + virtual const Json::Value &getCustomConfig() const override { - return _customConfig; + return _jsonConfig["custom_config"]; } + + virtual PluginBase *getPlugin(const std::string &name) override + { + return _pluginsManager.getPlugin(name); + } + virtual void addListener(const std::string &ip, uint16_t port, bool useSSL = false, @@ -229,7 +237,9 @@ class HttpAppFrameworkImpl : public HttpAppFramework int _staticFilesCacheTime = 5; std::unordered_map> _staticFilesCache; std::mutex _staticFilesCacheMutex; - Json::Value _customConfig; + //Json::Value _customConfig; + Json::Value _jsonConfig; + PluginsManager _pluginsManager; #if USE_ORM std::map _dbClientsMap; struct DbInfo diff --git a/lib/src/PluginsManager.cc b/lib/src/PluginsManager.cc new file mode 100644 index 00000000..e2fd2412 --- /dev/null +++ b/lib/src/PluginsManager.cc @@ -0,0 +1,100 @@ +/** + * + * PluginsManager.cc + * An Tao + * + * Copyright 2018, An Tao. All rights reserved. + * https://github.com/an-tao/drogon + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Drogon + * + */ + +#include "PluginsManager.h" +#include + +using namespace drogon; + +PluginsManager::~PluginsManager() +{ + // Shut down all plugins in reverse order of initializaiton. + for (auto iter = _initializedPlugins.rbegin(); iter != _initializedPlugins.rend(); iter++) + { + (*iter)->shutdown(); + } +} + +void PluginsManager::initializeAllPlugins(const Json::Value &configs, + const std::function &forEachCallback) +{ + assert(configs.isArray()); + std::vector plugins; + for (auto &config : configs) + { + auto name = config.get("name", "").asString(); + if (name.empty()) + continue; + auto pluginPtr = getPlugin(name); + assert(pluginPtr); + if (!pluginPtr) + continue; + auto configuration = config["config"]; + auto dependencies = config["dependencies"]; + pluginPtr->setConfig(configuration); + std::vector depsNames; + assert(dependencies.isArray() || dependencies.isNull()); + if (dependencies.isArray()) + { + //Is not null and is an array + for (auto &depName : dependencies) + { + auto *dp = getPlugin(depName.asString()); + if (dp) + { + pluginPtr->addDependency(dp); + } + else + { + LOG_FATAL << "Plugin " << depName.asString() << " not defined"; + abort(); + } + } + } + pluginPtr->setInitializedCallback([this](PluginBase *p) { + LOG_DEBUG << "Plugin " << p->className() << " initialized!"; + _initializedPlugins.push_back(p); + }); + plugins.push_back(pluginPtr); + } + //Initialize them, Depth first + for (auto plugin : plugins) + { + plugin->initialize(); + } +} + +PluginBase *PluginsManager::getPlugin(const std::string &pluginName) +{ + auto iter = _pluginsMap.find(pluginName); + if (iter == _pluginsMap.end()) + { + auto *p = DrClassMap::newObject(pluginName); + auto *pluginPtr = dynamic_cast(p); + if (!pluginPtr) + { + if (p) + delete p; + LOG_ERROR << "Plugin " << pluginName << " undefined!"; + return nullptr; + } + _pluginsMap[pluginName].reset(pluginPtr); + return pluginPtr; + } + else + { + return iter->second.get(); + } + return nullptr; +} \ No newline at end of file diff --git a/lib/src/PluginsManager.h b/lib/src/PluginsManager.h new file mode 100644 index 00000000..bf86e55a --- /dev/null +++ b/lib/src/PluginsManager.h @@ -0,0 +1,38 @@ +/** + * + * PluginsManager.h + * An Tao + * + * Copyright 2018, An Tao. All rights reserved. + * https://github.com/an-tao/drogon + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Drogon + * + */ + +#pragma once +#include +#include + +namespace drogon +{ + +typedef std::unique_ptr PluginBasePtr; + +class PluginsManager : trantor::NonCopyable +{ + public: + void initializeAllPlugins(const Json::Value &configs, + const std::function &forEachCallback); + + PluginBase *getPlugin(const std::string &pluginName); + ~PluginsManager(); + + private: + std::map _pluginsMap; + std::vector _initializedPlugins; +}; + +} // namespace drogon \ No newline at end of file