Merge pull request #99 from an-tao/custom_ctrl
Provides a way for users to create and initialize controllers
This commit is contained in:
commit
d0b9ed84ff
|
@ -0,0 +1,11 @@
|
|||
#include "CustomCtrl.h"
|
||||
//add definition of your processing function here
|
||||
|
||||
void CustomCtrl::hello(const HttpRequestPtr &req,
|
||||
const std::function<void(const HttpResponsePtr &)> &callback,
|
||||
const std::string &userName) const
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody("<P>" + _greetings + ", " + userName + "</P>");
|
||||
callback(resp);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include <drogon/HttpController.h>
|
||||
using namespace drogon;
|
||||
class CustomCtrl : public drogon::HttpController<CustomCtrl, false>
|
||||
{
|
||||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
//use METHOD_ADD to add your custom processing function here;
|
||||
METHOD_ADD(CustomCtrl::hello, "/{1}", Get, "CustomHeaderFilter"); //path is /customctrl/{arg1}
|
||||
METHOD_LIST_END
|
||||
|
||||
explicit CustomCtrl(const std::string &greetings) : _greetings(greetings) {}
|
||||
|
||||
void hello(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, const std::string &userName) const;
|
||||
|
||||
private:
|
||||
std::string _greetings;
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
*
|
||||
* CustomHeaderFilter.cc
|
||||
*
|
||||
*/
|
||||
|
||||
#include "CustomHeaderFilter.h"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
void CustomHeaderFilter::doFilter(const HttpRequestPtr &req,
|
||||
const FilterCallback &fcb,
|
||||
const FilterChainCallback &fccb)
|
||||
{
|
||||
if (req->getHeader(_field) == _value)
|
||||
{
|
||||
//Passed
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
//Check failed
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
res->setStatusCode(k500InternalServerError);
|
||||
fcb(res);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
*
|
||||
* CustomHeaderFilter.h
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/HttpFilter.h>
|
||||
using namespace drogon;
|
||||
|
||||
class CustomHeaderFilter : public HttpFilter<CustomHeaderFilter, false>
|
||||
{
|
||||
public:
|
||||
CustomHeaderFilter(const std::string &field, const std::string &value)
|
||||
: _field(field),
|
||||
_value(value) {}
|
||||
virtual void doFilter(const HttpRequestPtr &req,
|
||||
const FilterCallback &fcb,
|
||||
const FilterChainCallback &fccb) override;
|
||||
|
||||
private:
|
||||
std::string _field;
|
||||
std::string _value;
|
||||
};
|
|
@ -2,6 +2,8 @@
|
|||
#include <drogon/drogon.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "CustomCtrl.h"
|
||||
#include "CustomHeaderFilter.h"
|
||||
|
||||
using namespace drogon;
|
||||
class A : public DrObjectBase
|
||||
|
@ -141,9 +143,15 @@ int main()
|
|||
//drogon::HttpAppFramework::instance().enableDynamicViewsLoading({"/tmp/views"});
|
||||
app().loadConfigFile("config.example.json");
|
||||
auto &json = app().getCustomConfig();
|
||||
if(json.empty())
|
||||
if (json.empty())
|
||||
{
|
||||
std::cout << "empty custom config!" << std::endl;
|
||||
}
|
||||
//Install custom controller
|
||||
auto ctrlPtr = std::make_shared<CustomCtrl>("Hi");
|
||||
app().registerController(ctrlPtr);
|
||||
//Install custom filter
|
||||
auto filterPtr = std::make_shared<CustomHeaderFilter>("custom_header", "yes");
|
||||
app().registerFilter(filterPtr);
|
||||
app().run();
|
||||
}
|
||||
|
|
|
@ -532,7 +532,32 @@ void doTest(const HttpClientPtr &client, std::promise<int> &pro, bool isHttps =
|
|||
exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
/// Test controllers created and initialized by users
|
||||
req = HttpRequest::newHttpFormPostRequest();
|
||||
req->setMethod(drogon::Get);
|
||||
req->setPath("/customctrl/antao");
|
||||
req->addHeader("custom_header", "yes");
|
||||
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
|
||||
if (result == ReqResult::Ok)
|
||||
{
|
||||
auto ret = resp->getBody();
|
||||
if (ret == "<P>Hi, antao</P>")
|
||||
{
|
||||
outputGood(req, isHttps);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG << resp->getBody();
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
});
|
||||
/// Test form post
|
||||
req = HttpRequest::newHttpFormPostRequest();
|
||||
req->setPath("/api/v1/apitest/form");
|
||||
|
|
|
@ -14,14 +14,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/utils/ClassTraits.h>
|
||||
#include <stdio.h>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <cxxabi.h>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
|
@ -34,7 +35,22 @@ class DrClassMap
|
|||
static void registerClass(const std::string &className, const DrAllocFunc &func);
|
||||
static DrObjectBase *newObject(const std::string &className);
|
||||
static const std::shared_ptr<DrObjectBase> &getSingleInstance(const std::string &className);
|
||||
template <typename T>
|
||||
static std::shared_ptr<T> getSingleInstance()
|
||||
{
|
||||
static_assert(internal::IsSubClass<T, DrObjectBase>::value, "T must be a sub-class of DrObjectBase");
|
||||
return std::dynamic_pointer_cast<T>(getSingleInstance(T::classTypeName()));
|
||||
}
|
||||
static void setSingleInstance(const std::shared_ptr<DrObjectBase> &ins);
|
||||
static std::vector<std::string> getAllClassName();
|
||||
static const std::string demangle(const char *mangled_name)
|
||||
{
|
||||
std::size_t len = 0;
|
||||
int status = 0;
|
||||
std::unique_ptr<char, decltype(&std::free)> ptr(
|
||||
__cxxabiv1::__cxa_demangle(mangled_name, nullptr, &len, &status), &std::free);
|
||||
return ptr.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::unordered_map<std::string, DrAllocFunc> &getMap();
|
||||
|
|
|
@ -16,8 +16,9 @@
|
|||
|
||||
#include <drogon/DrClassMap.h>
|
||||
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
class DrObjectBase
|
||||
|
@ -32,14 +33,6 @@ class DrObjectBase
|
|||
{
|
||||
return (className() == class_name);
|
||||
}
|
||||
static const std::string demangle(const char *mangled_name)
|
||||
{
|
||||
std::size_t len = 0;
|
||||
int status = 0;
|
||||
std::unique_ptr<char, decltype(&std::free)> ptr(
|
||||
__cxxabiv1::__cxa_demangle(mangled_name, nullptr, &len, &status), &std::free);
|
||||
return ptr.get();
|
||||
}
|
||||
virtual ~DrObjectBase() {}
|
||||
};
|
||||
|
||||
|
@ -74,15 +67,24 @@ class DrObject : public virtual DrObjectBase
|
|||
{
|
||||
public:
|
||||
DrAllocator()
|
||||
{
|
||||
registerClass<T>();
|
||||
}
|
||||
const std::string &className() const
|
||||
{
|
||||
static std::string className = DrClassMap::demangle(typeid(T).name());
|
||||
return className;
|
||||
}
|
||||
template <typename D>
|
||||
typename std::enable_if<std::is_default_constructible<D>::value, void>::type registerClass()
|
||||
{
|
||||
DrClassMap::registerClass(className(), []() -> DrObjectBase * {
|
||||
return new T;
|
||||
});
|
||||
}
|
||||
const std::string &className() const
|
||||
template <typename D>
|
||||
typename std::enable_if<!std::is_default_constructible<D>::value, void>::type registerClass()
|
||||
{
|
||||
static std::string className = demangle(typeid(T).name());
|
||||
return className;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
typedef HttpViewData DrTemplateData;
|
||||
|
||||
/// The templating engine class
|
||||
|
@ -35,7 +36,7 @@ class DrTemplateBase : public virtual DrObjectBase
|
|||
/**
|
||||
* The @param templateName represents the name of the template file.
|
||||
* A template file is a description file with a special format. Its extension is
|
||||
* usually .csp and can be omitted. The user should preprocess the template file
|
||||
* usually .csp. The user should preprocess the template file
|
||||
* with the drogon_ctl tool to create c++ source files.
|
||||
*/
|
||||
static std::shared_ptr<DrTemplateBase> newTemplate(std::string templateName);
|
||||
|
@ -49,4 +50,5 @@ class DrTemplateBase : public virtual DrObjectBase
|
|||
virtual ~DrTemplateBase(){};
|
||||
DrTemplateBase(){};
|
||||
};
|
||||
|
||||
} // namespace drogon
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <drogon/orm/DbClient.h>
|
||||
#endif
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <drogon/utils/ClassTraits.h>
|
||||
#include <drogon/HttpBinder.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <drogon/DrObject.h>
|
||||
|
@ -58,6 +59,10 @@ inline std::string getGitCommit()
|
|||
return VERSION_MD5;
|
||||
}
|
||||
|
||||
class HttpControllerBase;
|
||||
class HttpSimpleControllerBase;
|
||||
class WebSocketControllerBase;
|
||||
|
||||
class HttpAppFramework : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
|
@ -115,7 +120,7 @@ class HttpAppFramework : public trantor::NonCopyable
|
|||
{
|
||||
static_assert(IsPlugin<T>::value, "The Template parameter must be a subclass of PluginBase");
|
||||
assert(isRunning());
|
||||
return dynamic_cast<T *>(getPlugin(T::className()));
|
||||
return dynamic_cast<T *>(getPlugin(T::classTypeName()));
|
||||
}
|
||||
|
||||
///Get the plugin object registered in the framework
|
||||
|
@ -216,6 +221,54 @@ class HttpAppFramework : public trantor::NonCopyable
|
|||
const std::vector<std::string> &filters =
|
||||
std::vector<std::string>()) = 0;
|
||||
|
||||
/// Register controller objects created and initialized by the user
|
||||
/**
|
||||
* Drogon can only automatically create controllers using the default constructor.
|
||||
* Sometimes users want to be able to create controllers using constructors with
|
||||
* parameters. Controllers created by user in this way should be registered to the framework
|
||||
* via this method.
|
||||
* The macro or configuration file is still valid for the path routing configuration
|
||||
* of the controller created by users.
|
||||
*
|
||||
* NOTE:
|
||||
* The declaration of the controller class must be as follows:
|
||||
* class ApiTest : public drogon::HttpController<ApiTest, false>
|
||||
* {
|
||||
* public:
|
||||
* ApiTest(const std::string &str);
|
||||
* ...
|
||||
* };
|
||||
* The second template parameter must be explicitly set to false to disable automatic creation.
|
||||
* And then user can create and register it somewhere as follows:
|
||||
* auto ctrlPtr=std::make_shared<ApiTest>("hello world");
|
||||
* drogon::app().registerController(ctrlPtr);
|
||||
* This method should be called before calling the app().run() method.
|
||||
*/
|
||||
template <typename T>
|
||||
void registerController(const std::shared_ptr<T> &ctrlPtr)
|
||||
{
|
||||
static_assert(internal::IsSubClass<T, HttpControllerBase>::value ||
|
||||
internal::IsSubClass<T, HttpSimpleControllerBase>::value ||
|
||||
internal::IsSubClass<T, WebSocketControllerBase>::value,
|
||||
"Error! Only controller objects can be registered here");
|
||||
static_assert(!T::isAutoCreation, "Controllers created and initialized automatically by drogon cannot be registered here");
|
||||
DrClassMap::setSingleInstance(ctrlPtr);
|
||||
T::initPathRouting();
|
||||
}
|
||||
|
||||
/// Register filter objects created and initialized by the user
|
||||
/**
|
||||
* This method is similar to the above method.
|
||||
*/
|
||||
template <typename T>
|
||||
void registerFilter(const std::shared_ptr<T> &filterPtr)
|
||||
{
|
||||
static_assert(internal::IsSubClass<T, HttpFilterBase>::value,
|
||||
"Error! Only fitler objects can be registered here");
|
||||
static_assert(!T::isAutoCreation, "Filters created and initialized automatically by drogon cannot be registered here");
|
||||
DrClassMap::setSingleInstance(filterPtr);
|
||||
}
|
||||
|
||||
///Get the custom configuration defined by users in the configuration file.
|
||||
virtual const Json::Value &getCustomConfig() const = 0;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <drogon/utils/FunctionTraits.h>
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <drogon/DrObject.h>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
@ -109,15 +110,13 @@ class HttpBinder : public HttpBinderBase
|
|||
FUNCTION _func;
|
||||
|
||||
typedef FunctionTraits<FUNCTION> traits;
|
||||
template <
|
||||
std::size_t Index>
|
||||
template <std::size_t Index>
|
||||
using nth_argument_type = typename traits::template argument<Index>;
|
||||
|
||||
static const size_t argument_count = traits::arity;
|
||||
|
||||
template <
|
||||
typename... Values,
|
||||
std::size_t Boundary = argument_count>
|
||||
template <typename... Values,
|
||||
std::size_t Boundary = argument_count>
|
||||
typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
|
||||
std::list<std::string> &pathParameter,
|
||||
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> callback,
|
||||
|
@ -152,14 +151,25 @@ class HttpBinder : public HttpBinderBase
|
|||
callFunction(req, callback, std::move(values)...);
|
||||
}
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction>
|
||||
typename std::enable_if<isClassFunction, void>::type callFunction(
|
||||
bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass>
|
||||
typename std::enable_if<isClassFunction && !isDrObjectClass, void>::type callFunction(
|
||||
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> callback,
|
||||
Values &&... values)
|
||||
{
|
||||
auto &obj = getControllerObj<typename traits::class_type>();
|
||||
static auto &obj = getControllerObj<typename traits::class_type>();
|
||||
(obj.*_func)(req, callback, std::move(values)...);
|
||||
};
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass>
|
||||
typename std::enable_if<isClassFunction && isDrObjectClass, void>::type callFunction(
|
||||
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> callback,
|
||||
Values &&... values)
|
||||
{
|
||||
static auto objPtr = DrClassMap::getSingleInstance<typename traits::class_type>();
|
||||
(*objPtr.*_func)(req, callback, std::move(values)...);
|
||||
};
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction>
|
||||
typename std::enable_if<!isClassFunction, void>::type callFunction(
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
|
||||
/// For more details on the class, see the wiki site (the 'HttpController' section)
|
||||
|
||||
#define METHOD_LIST_BEGIN \
|
||||
static void initMethods() \
|
||||
#define METHOD_LIST_BEGIN \
|
||||
static void initPathRouting() \
|
||||
{
|
||||
|
||||
#define METHOD_ADD(method, pattern, filters...) \
|
||||
|
@ -34,15 +34,21 @@
|
|||
|
||||
#define METHOD_LIST_END \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
protected:
|
||||
}
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
template <typename T>
|
||||
class HttpController : public DrObject<T>
|
||||
|
||||
class HttpControllerBase
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class HttpController : public DrObject<T>, public HttpControllerBase
|
||||
{
|
||||
public:
|
||||
static const bool isAutoCreation = AutoCreation;
|
||||
|
||||
protected:
|
||||
template <typename FUNCTION>
|
||||
static void registerMethod(FUNCTION &&function,
|
||||
|
@ -60,12 +66,12 @@ class HttpController : public DrObject<T>
|
|||
}
|
||||
if (pattern.empty() || pattern[0] == '/')
|
||||
app().registerHandler(path + pattern,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods);
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods);
|
||||
else
|
||||
app().registerHandler(path + "/" + pattern,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods);
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -74,7 +80,8 @@ class HttpController : public DrObject<T>
|
|||
public:
|
||||
methodRegister()
|
||||
{
|
||||
T::initMethods();
|
||||
if (AutoCreation)
|
||||
T::initPathRouting();
|
||||
}
|
||||
};
|
||||
//use static value to register controller method in framework before main();
|
||||
|
@ -84,6 +91,6 @@ class HttpController : public DrObject<T>
|
|||
return &_register;
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
typename HttpController<T>::methodRegister HttpController<T>::_register;
|
||||
template <typename T, bool AutoCreation>
|
||||
typename HttpController<T, AutoCreation>::methodRegister HttpController<T, AutoCreation>::_register;
|
||||
} // namespace drogon
|
||||
|
|
|
@ -33,10 +33,11 @@ class HttpFilterBase : public virtual DrObjectBase
|
|||
const FilterChainCallback &fccb) = 0;
|
||||
virtual ~HttpFilterBase() {}
|
||||
};
|
||||
template <typename T>
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class HttpFilter : public DrObject<T>, public HttpFilterBase
|
||||
{
|
||||
public:
|
||||
static const bool isAutoCreation = AutoCreation;
|
||||
virtual ~HttpFilter() {}
|
||||
};
|
||||
} // namespace drogon
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#define PATH_LIST_BEGIN \
|
||||
static void ___paths___() \
|
||||
#define PATH_LIST_BEGIN \
|
||||
static void initPathRouting() \
|
||||
{
|
||||
|
||||
#define PATH_ADD(path, filters...) __registerSelf(path, {filters});
|
||||
|
@ -30,7 +30,7 @@
|
|||
}
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
|
||||
class HttpSimpleControllerBase : public virtual DrObjectBase
|
||||
{
|
||||
public:
|
||||
|
@ -38,10 +38,11 @@ class HttpSimpleControllerBase : public virtual DrObjectBase
|
|||
virtual ~HttpSimpleControllerBase() {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class HttpSimpleController : public DrObject<T>, public HttpSimpleControllerBase
|
||||
{
|
||||
public:
|
||||
static const bool isAutoCreation = AutoCreation;
|
||||
virtual ~HttpSimpleController() {}
|
||||
|
||||
protected:
|
||||
|
@ -58,16 +59,11 @@ class HttpSimpleController : public DrObject<T>, public HttpSimpleControllerBase
|
|||
public:
|
||||
pathRegister()
|
||||
{
|
||||
T::___paths___();
|
||||
if (AutoCreation)
|
||||
{
|
||||
T::initPathRouting();
|
||||
}
|
||||
}
|
||||
// protected:
|
||||
// void _register(const std::string &className, const std::vector<std::string> &paths)
|
||||
// {
|
||||
// for (auto const &reqPath : paths)
|
||||
// {
|
||||
// std::cout << "register controller class " << className << " on path " << reqPath << std::endl;
|
||||
// }
|
||||
// }
|
||||
};
|
||||
friend pathRegister;
|
||||
static pathRegister _register;
|
||||
|
@ -76,7 +72,7 @@ class HttpSimpleController : public DrObject<T>, public HttpSimpleControllerBase
|
|||
return &_register;
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
typename HttpSimpleController<T>::pathRegister HttpSimpleController<T>::_register;
|
||||
template <typename T, bool AutoCreation>
|
||||
typename HttpSimpleController<T, AutoCreation>::pathRegister HttpSimpleController<T, AutoCreation>::_register;
|
||||
|
||||
} // namespace drogon
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#define WS_PATH_LIST_BEGIN \
|
||||
static std::vector<std::pair<std::string, std::vector<std::string>>> paths() \
|
||||
{ \
|
||||
#define WS_PATH_LIST_BEGIN \
|
||||
static std::vector<std::pair<std::string, std::vector<std::string>>> __paths() \
|
||||
{ \
|
||||
std::vector<std::pair<std::string, std::vector<std::string>>> vet;
|
||||
|
||||
#define WS_PATH_ADD(path, filters...) \
|
||||
|
@ -34,8 +34,10 @@
|
|||
#define WS_PATH_LIST_END \
|
||||
return vet; \
|
||||
}
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
class WebSocketControllerBase : public virtual DrObjectBase
|
||||
{
|
||||
public:
|
||||
|
@ -51,11 +53,24 @@ class WebSocketControllerBase : public virtual DrObjectBase
|
|||
};
|
||||
|
||||
typedef std::shared_ptr<WebSocketControllerBase> WebSocketControllerBasePtr;
|
||||
template <typename T>
|
||||
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class WebSocketController : public DrObject<T>, public WebSocketControllerBase
|
||||
{
|
||||
public:
|
||||
static const bool isAutoCreation = AutoCreation;
|
||||
virtual ~WebSocketController() {}
|
||||
static void initPathRouting()
|
||||
{
|
||||
auto vPaths = T::__paths();
|
||||
for (auto const &path : vPaths)
|
||||
{
|
||||
LOG_TRACE << "register websocket controller (" << WebSocketController<T>::classTypeName() << ") on path:" << path.first;
|
||||
HttpAppFramework::instance().registerWebSocketController(path.first,
|
||||
WebSocketController<T>::classTypeName(),
|
||||
path.second);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
WebSocketController() {}
|
||||
|
@ -66,25 +81,11 @@ class WebSocketController : public DrObject<T>, public WebSocketControllerBase
|
|||
public:
|
||||
pathRegister()
|
||||
{
|
||||
auto vPaths = T::paths();
|
||||
|
||||
for (auto const &path : vPaths)
|
||||
if (AutoCreation)
|
||||
{
|
||||
LOG_TRACE << "register websocket controller (" << WebSocketController<T>::classTypeName() << ") on path:" << path.first;
|
||||
HttpAppFramework::instance().registerWebSocketController(path.first,
|
||||
WebSocketController<T>::classTypeName(),
|
||||
path.second);
|
||||
T::initPathRouting();
|
||||
}
|
||||
}
|
||||
|
||||
// protected:
|
||||
// void _register(const std::string &className, const std::vector<std::string> &paths)
|
||||
// {
|
||||
// for (auto const &reqPath : paths)
|
||||
// {
|
||||
// std::cout << "register controller class " << className << " on path " << reqPath << std::endl;
|
||||
// }
|
||||
// }
|
||||
};
|
||||
friend pathRegister;
|
||||
static pathRegister _register;
|
||||
|
@ -93,7 +94,7 @@ class WebSocketController : public DrObject<T>, public WebSocketControllerBase
|
|||
return &_register;
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
typename WebSocketController<T>::pathRegister WebSocketController<T>::_register;
|
||||
template <typename T, bool AutoCreation>
|
||||
typename WebSocketController<T, AutoCreation>::pathRegister WebSocketController<T, AutoCreation>::_register;
|
||||
|
||||
} // namespace drogon
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
*
|
||||
* ClassTraits.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 <type_traits>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
/// This template is used to check whether S is a subclass of B.
|
||||
template <typename S, typename B>
|
||||
struct IsSubClass
|
||||
{
|
||||
typedef typename std::remove_cv<typename std::remove_reference<S>::type>::type SubType;
|
||||
typedef typename std::remove_cv<typename std::remove_reference<B>::type>::type BaseType;
|
||||
static char test(void *) { return 0; }
|
||||
static int test(BaseType *) { return 0; }
|
||||
static const bool value = (sizeof(test((SubType *)nullptr)) == sizeof(int));
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace drogon
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/utils/ClassTraits.h>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
|
@ -38,6 +40,7 @@ struct FunctionTraits : public FunctionTraits<
|
|||
decltype(&std::remove_reference<Function>::type::operator())>
|
||||
{
|
||||
static const bool isClassFunction = false;
|
||||
static const bool isDrObjectClass = false;
|
||||
typedef void class_type;
|
||||
static const std::string name()
|
||||
{
|
||||
|
@ -46,14 +49,13 @@ struct FunctionTraits : public FunctionTraits<
|
|||
};
|
||||
|
||||
//class instance method of const object
|
||||
template <
|
||||
typename ClassType,
|
||||
typename ReturnType,
|
||||
typename... Arguments>
|
||||
struct FunctionTraits<
|
||||
ReturnType (ClassType::*)(Arguments...) const> : FunctionTraits<ReturnType (*)(Arguments...)>
|
||||
template <typename ClassType,
|
||||
typename ReturnType,
|
||||
typename... Arguments>
|
||||
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...) const> : FunctionTraits<ReturnType (*)(Arguments...)>
|
||||
{
|
||||
static const bool isClassFunction = true;
|
||||
static const bool isDrObjectClass = IsSubClass<ClassType, DrObject<ClassType>>::value;
|
||||
typedef ClassType class_type;
|
||||
static const std::string name() { return std::string("Class Function"); }
|
||||
};
|
||||
|
@ -63,10 +65,10 @@ template <
|
|||
typename ClassType,
|
||||
typename ReturnType,
|
||||
typename... Arguments>
|
||||
struct FunctionTraits<
|
||||
ReturnType (ClassType::*)(Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
|
||||
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
|
||||
{
|
||||
static const bool isClassFunction = true;
|
||||
static const bool isDrObjectClass = IsSubClass<ClassType, DrObject<ClassType>>::value;
|
||||
typedef ClassType class_type;
|
||||
static const std::string name() { return std::string("Class Function"); }
|
||||
};
|
||||
|
@ -100,6 +102,7 @@ struct FunctionTraits<
|
|||
typedef void class_type;
|
||||
static const bool isHTTPFunction = false;
|
||||
static const bool isClassFunction = false;
|
||||
static const bool isDrObjectClass = false;
|
||||
static const std::string name() { return std::string("Normal or Static Function"); }
|
||||
};
|
||||
|
||||
|
|
|
@ -18,12 +18,31 @@
|
|||
using namespace drogon;
|
||||
//std::map <std::string,DrAllocFunc> * DrClassMap::classMap=nullptr;
|
||||
//std::once_flag DrClassMap::flag;
|
||||
namespace drogon
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
static std::unordered_map<std::string, std::shared_ptr<DrObjectBase>> &getObjsMap()
|
||||
{
|
||||
static std::unordered_map<std::string, std::shared_ptr<DrObjectBase>> singleInstanceMap;
|
||||
return singleInstanceMap;
|
||||
}
|
||||
|
||||
static std::mutex &getMapMutex()
|
||||
{
|
||||
static std::mutex mtx;
|
||||
return mtx;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace drogon
|
||||
|
||||
void DrClassMap::registerClass(const std::string &className, const DrAllocFunc &func)
|
||||
{
|
||||
//std::cout<<"register class:"<<className<<std::endl;
|
||||
|
||||
getMap().insert(std::make_pair(className, func));
|
||||
}
|
||||
|
||||
DrObjectBase *DrClassMap::newObject(const std::string &className)
|
||||
{
|
||||
auto iter = getMap().find(className);
|
||||
|
@ -34,10 +53,11 @@ DrObjectBase *DrClassMap::newObject(const std::string &className)
|
|||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::shared_ptr<DrObjectBase> &DrClassMap::getSingleInstance(const std::string &className)
|
||||
{
|
||||
static std::unordered_map<std::string, std::shared_ptr<DrObjectBase>> singleInstanceMap;
|
||||
static std::mutex mtx;
|
||||
auto &mtx = internal::getMapMutex();
|
||||
auto &singleInstanceMap = internal::getObjsMap();
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
auto iter = singleInstanceMap.find(className);
|
||||
if (iter != singleInstanceMap.end())
|
||||
|
@ -45,6 +65,15 @@ const std::shared_ptr<DrObjectBase> &DrClassMap::getSingleInstance(const std::st
|
|||
singleInstanceMap[className] = std::shared_ptr<DrObjectBase>(newObject(className));
|
||||
return singleInstanceMap[className];
|
||||
}
|
||||
|
||||
void DrClassMap::setSingleInstance(const std::shared_ptr<DrObjectBase> &ins)
|
||||
{
|
||||
auto &mtx = internal::getMapMutex();
|
||||
auto &singleInstanceMap = internal::getObjsMap();
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
singleInstanceMap[ins->className()] = ins;
|
||||
}
|
||||
|
||||
std::vector<std::string> DrClassMap::getAllClassName()
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
@ -54,6 +83,7 @@ std::vector<std::string> DrClassMap::getAllClassName()
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, DrAllocFunc> &DrClassMap::getMap()
|
||||
{
|
||||
static std::unordered_map<std::string, DrAllocFunc> map;
|
||||
|
|
|
@ -30,7 +30,7 @@ void WebsocketControllersRouter::registerWebSocketController(const std::string &
|
|||
assert(!ctrlName.empty());
|
||||
std::string path(pathName);
|
||||
std::transform(pathName.begin(), pathName.end(), path.begin(), tolower);
|
||||
auto objPtr = std::shared_ptr<DrObjectBase>(DrClassMap::newObject(ctrlName));
|
||||
auto objPtr = DrClassMap::getSingleInstance(ctrlName);
|
||||
auto ctrlPtr = std::dynamic_pointer_cast<WebSocketControllerBase>(objPtr);
|
||||
assert(ctrlPtr);
|
||||
std::lock_guard<std::mutex> guard(_websockCtrlMutex);
|
||||
|
|
Loading…
Reference in New Issue