Add support for plugins
This commit is contained in:
parent
fd5c02c89f
commit
aad06fdc3a
|
@ -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)
|
||||
|
|
|
@ -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": {}
|
||||
}
|
|
@ -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 <project_name> //"
|
||||
"create a project named project_name\n\n"
|
||||
"drogon_ctl create model <model_path> //"
|
||||
|
|
|
@ -100,7 +100,7 @@ void create_filter::handleCommand(std::vector<std::string> ¶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);
|
||||
}
|
||||
|
|
|
@ -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 <drogon/DrTemplateBase.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
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<std::string> ¶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);
|
||||
}
|
||||
}
|
|
@ -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 <drogon/DrObject.h>
|
||||
#include "CommandHandler.h"
|
||||
using namespace drogon;
|
||||
namespace drogon_ctl
|
||||
{
|
||||
class create_plugin : public DrObject<create_plugin>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual std::string script() override { return "create plugin class files"; }
|
||||
|
||||
protected:
|
||||
std::string _outputPath = ".";
|
||||
};
|
||||
} // namespace drogon_ctl
|
|
@ -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);
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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": {}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
*
|
||||
* {{filename}}.cc
|
||||
*
|
||||
*/
|
||||
|
||||
#include "{{filename}}.h"
|
||||
|
||||
using namespace drogon;
|
||||
<%c++auto namespaceStr=@@.get<std::string>("namespaceString");
|
||||
if(!namespaceStr.empty())
|
||||
$$<<"using namespace "<<namespaceStr<<";\n";
|
||||
%>
|
||||
|
||||
void {{className}}::initAndStart(const Json::Value &config)
|
||||
{
|
||||
/// Initialize and start the plugin
|
||||
}
|
||||
|
||||
void {{className}}::shutdown()
|
||||
{
|
||||
/// Shutdown the plugin
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
*
|
||||
* {{filename}}.h
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/plugins/Plugin.h>
|
||||
using namespace drogon;
|
||||
<%c++
|
||||
auto namespaceVector=@@.get<std::vector<std::string>>("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<namespaceVector.size();i++){%>
|
||||
}
|
||||
<%c++}%>
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
*
|
||||
* DoNothingPlugin.h
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/plugins/Plugin.h>
|
||||
using namespace drogon;
|
||||
|
||||
|
||||
class DoNothingPlugin : public Plugin<DoNothingPlugin>
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
*
|
||||
* TestPlugin.cc
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TestPlugin.h"
|
||||
#include <unistd.h>
|
||||
|
||||
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();
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
*
|
||||
* TestPlugin.h
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/plugins/Plugin.h>
|
||||
using namespace drogon;
|
||||
|
||||
class TestPlugin : public Plugin<TestPlugin>
|
||||
{
|
||||
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;
|
||||
};
|
|
@ -31,12 +31,15 @@
|
|||
#include <drogon/NotFound.h>
|
||||
#include <drogon/HttpClient.h>
|
||||
#include <drogon/MultiPart.h>
|
||||
#include <drogon/plugins/Plugin.h>
|
||||
#include <trantor/net/EventLoop.h>
|
||||
#include <drogon/CacheMap.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
|
||||
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 <typename T>
|
||||
T *getPlugin()
|
||||
{
|
||||
static_assert(IsPlugin<T>::value, "The Template parameter must be a subclass of PluginBase");
|
||||
assert(isRunning());
|
||||
return dynamic_cast<T *>(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;
|
||||
|
||||
|
|
|
@ -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 <drogon/DrObject.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <json/json.h>
|
||||
#include <memory>
|
||||
|
||||
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<void(PluginBase *)> &cb) { _initializedCallback = cb; }
|
||||
Json::Value _config;
|
||||
std::vector<PluginBase *> _dependencies;
|
||||
std::function<void(PluginBase *)> _initializedCallback;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsPlugin
|
||||
{
|
||||
typedef typename std::remove_cv<typename std::remove_reference<T>::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 <typename T>
|
||||
class Plugin : public PluginBase, public DrObject<T>
|
||||
{
|
||||
public:
|
||||
virtual ~Plugin() {}
|
||||
|
||||
protected:
|
||||
Plugin() {}
|
||||
};
|
||||
|
||||
} // namespace drogon
|
|
@ -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<CacheMap<std::string, HttpResponsePtr>>(new CacheMap<std::string, HttpResponsePtr>(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)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "HttpControllersRouter.h"
|
||||
#include "HttpSimpleControllersRouter.h"
|
||||
#include "WebsocketControllersRouter.h"
|
||||
#include "PluginsManager.h"
|
||||
|
||||
#include <drogon/HttpAppFramework.h>
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
|
@ -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<std::string, std::weak_ptr<HttpResponse>> _staticFilesCache;
|
||||
std::mutex _staticFilesCacheMutex;
|
||||
Json::Value _customConfig;
|
||||
//Json::Value _customConfig;
|
||||
Json::Value _jsonConfig;
|
||||
PluginsManager _pluginsManager;
|
||||
#if USE_ORM
|
||||
std::map<std::string, orm::DbClientPtr> _dbClientsMap;
|
||||
struct DbInfo
|
||||
|
|
|
@ -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 <trantor/utils/Logger.h>
|
||||
|
||||
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<void(PluginBase *)> &forEachCallback)
|
||||
{
|
||||
assert(configs.isArray());
|
||||
std::vector<PluginBase *> 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<std::string> 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<PluginBase *>(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;
|
||||
}
|
|
@ -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 <drogon/plugins/Plugin.h>
|
||||
#include <map>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
typedef std::unique_ptr<PluginBase> PluginBasePtr;
|
||||
|
||||
class PluginsManager : trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
void initializeAllPlugins(const Json::Value &configs,
|
||||
const std::function<void(PluginBase *)> &forEachCallback);
|
||||
|
||||
PluginBase *getPlugin(const std::string &pluginName);
|
||||
~PluginsManager();
|
||||
|
||||
private:
|
||||
std::map<std::string, PluginBasePtr> _pluginsMap;
|
||||
std::vector<PluginBase *> _initializedPlugins;
|
||||
};
|
||||
|
||||
} // namespace drogon
|
Loading…
Reference in New Issue