mirror of
https://github.com/Relintai/rcpp_framework.git
synced 2024-11-14 04:57:21 +01:00
Removed the templating engine and most of the routing and controller logic from drogon.
This commit is contained in:
parent
1dfd747b41
commit
d2b0ff2e22
@ -1,130 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @file DrClassMap.h
|
||||
* @author 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/exports.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#ifndef _MSC_VER
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
namespace drogon {
|
||||
class DrObjectBase;
|
||||
using DrAllocFunc = std::function<DrObjectBase *()>;
|
||||
|
||||
/**
|
||||
* @brief A map class which can create DrObjects from names.
|
||||
*/
|
||||
class DROGON_EXPORT DrClassMap {
|
||||
public:
|
||||
/**
|
||||
* @brief Register a class into the map
|
||||
*
|
||||
* @param className The name of the class
|
||||
* @param func The function which can create a new instance of the class.
|
||||
*/
|
||||
static void registerClass(const std::string &className,
|
||||
const DrAllocFunc &func);
|
||||
|
||||
/**
|
||||
* @brief Create a new instance of the class named by className
|
||||
*
|
||||
* @param className The name of the class
|
||||
* @return DrObjectBase* The pointer to the newly created instance.
|
||||
*/
|
||||
static DrObjectBase *newObject(const std::string &className);
|
||||
|
||||
/**
|
||||
* @brief Get the singleton object of the class named by className
|
||||
*
|
||||
* @param className The name of the class
|
||||
* @return const std::shared_ptr<DrObjectBase>& The smart pointer to the
|
||||
* instance.
|
||||
*/
|
||||
static const std::shared_ptr<DrObjectBase> &getSingleInstance(
|
||||
const std::string &className);
|
||||
|
||||
/**
|
||||
* @brief Get the singleton T type object
|
||||
*
|
||||
* @tparam T The type of the class
|
||||
* @return std::shared_ptr<T> The smart pointer to the instance.
|
||||
* @note The T must be a subclass of the DrObjectBase class.
|
||||
*/
|
||||
template <typename T>
|
||||
static std::shared_ptr<T> getSingleInstance() {
|
||||
static_assert(std::is_base_of<DrObjectBase, T>::value,
|
||||
"T must be a sub-class of DrObjectBase");
|
||||
static auto const singleton =
|
||||
std::dynamic_pointer_cast<T>(getSingleInstance(T::classTypeName()));
|
||||
assert(singleton);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a singleton object into the map.
|
||||
*
|
||||
* @param ins The smart pointer to the instance.
|
||||
*/
|
||||
static void setSingleInstance(const std::shared_ptr<DrObjectBase> &ins);
|
||||
|
||||
/**
|
||||
* @brief Get all names of classes registered in the map.
|
||||
*
|
||||
* @return std::vector<std::string> the vector of class names.
|
||||
*/
|
||||
static std::vector<std::string> getAllClassName();
|
||||
|
||||
/**
|
||||
* @brief demangle the type name which is returned by typeid(T).name().
|
||||
*
|
||||
* @param mangled_name The type name which is returned by typeid(T).name().
|
||||
* @return std::string The human readable type name.
|
||||
*/
|
||||
static std::string demangle(const char *mangled_name) {
|
||||
#ifndef _MSC_VER
|
||||
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);
|
||||
if (status == 0) {
|
||||
return std::string(ptr.get());
|
||||
}
|
||||
LOG_ERROR << "Demangle error!";
|
||||
return "";
|
||||
#else
|
||||
auto pos = strstr(mangled_name, " ");
|
||||
if (pos == nullptr)
|
||||
return std::string{ mangled_name };
|
||||
else
|
||||
return std::string{ pos + 1 };
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::unordered_map<std::string, DrAllocFunc> &getMap();
|
||||
};
|
||||
|
||||
} // namespace drogon
|
@ -1,108 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @file DrObject.h
|
||||
* @author 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/DrClassMap.h>
|
||||
#include <drogon/exports.h>
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4250)
|
||||
#endif
|
||||
|
||||
namespace drogon {
|
||||
/**
|
||||
* @brief The base class for all drogon reflection classes.
|
||||
*
|
||||
*/
|
||||
class DROGON_EXPORT DrObjectBase {
|
||||
public:
|
||||
/**
|
||||
* @brief Get the class name
|
||||
*
|
||||
* @return const std::string& the class name
|
||||
*/
|
||||
virtual const std::string &className() const {
|
||||
static const std::string name{ "DrObjectBase" };
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return true if the class name is 'class_name'
|
||||
*/
|
||||
virtual bool isClass(const std::string &class_name) const {
|
||||
return (className() == class_name);
|
||||
}
|
||||
virtual ~DrObjectBase() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* a class template to
|
||||
* implement the reflection function of creating the class object by class name
|
||||
*/
|
||||
template <typename T>
|
||||
class DrObject : public virtual DrObjectBase {
|
||||
public:
|
||||
virtual const std::string &className() const override {
|
||||
return alloc_.className();
|
||||
}
|
||||
static const std::string &classTypeName() {
|
||||
return alloc_.className();
|
||||
}
|
||||
|
||||
virtual bool isClass(const std::string &class_name) const override {
|
||||
return (className() == class_name);
|
||||
}
|
||||
|
||||
protected:
|
||||
// protect constructor to make this class only inheritable
|
||||
DrObject() = default;
|
||||
~DrObject() override = default;
|
||||
|
||||
private:
|
||||
class DrAllocator {
|
||||
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; });
|
||||
}
|
||||
template <typename D>
|
||||
typename std::enable_if<!std::is_default_constructible<D>::value,
|
||||
void>::type
|
||||
registerClass() {
|
||||
}
|
||||
};
|
||||
|
||||
// use static val to register allocator function for class T;
|
||||
static DrAllocator alloc_;
|
||||
};
|
||||
template <typename T>
|
||||
typename DrObject<T>::DrAllocator DrObject<T>::alloc_;
|
||||
|
||||
} // namespace drogon
|
@ -1,27 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* DrTemplate.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 <drogon/DrTemplateBase.h>
|
||||
namespace drogon {
|
||||
template <typename T>
|
||||
class DrTemplate : public DrObject<T>, public DrTemplateBase {
|
||||
protected:
|
||||
DrTemplate() {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace drogon
|
@ -1,56 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @file DrTemplateBase.h
|
||||
* @author 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 <drogon/HttpViewData.h>
|
||||
#include <drogon/exports.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace drogon {
|
||||
using DrTemplateData = HttpViewData;
|
||||
|
||||
/// The templating engine class
|
||||
/**
|
||||
* This class can generate a text string from the template file and template
|
||||
* data.
|
||||
* For more details on the template file, see the wiki site (the 'View' section)
|
||||
*/
|
||||
class DROGON_EXPORT DrTemplateBase : public virtual DrObjectBase {
|
||||
public:
|
||||
/// Create an object of the implementation class
|
||||
/**
|
||||
* @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. The user should preprocess the template file with the
|
||||
* drogon_ctl tool to create c++ source files.
|
||||
*/
|
||||
static std::shared_ptr<DrTemplateBase> newTemplate(
|
||||
const std::string &templateName);
|
||||
|
||||
/// Generate the text string
|
||||
/**
|
||||
* @param data represents data rendered in the string in a format
|
||||
* according to the template file.
|
||||
*/
|
||||
virtual std::string genText(
|
||||
const DrTemplateData &data = DrTemplateData()) = 0;
|
||||
|
||||
virtual ~DrTemplateBase(){};
|
||||
DrTemplateBase(){};
|
||||
};
|
||||
|
||||
} // namespace drogon
|
@ -15,14 +15,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <drogon/CacheMap.h>
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/HttpBinder.h>
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <drogon/IntranetIpFilter.h>
|
||||
#include <drogon/LocalHostFilter.h>
|
||||
#include <drogon/MultiPart.h>
|
||||
#include <drogon/NotFound.h>
|
||||
#include <drogon/drogon_callbacks.h>
|
||||
#include <drogon/exports.h>
|
||||
#include <drogon/plugins/Plugin.h>
|
||||
@ -431,6 +428,8 @@ public:
|
||||
std::vector<internal::HttpConstraint>{},
|
||||
const std::string &handlerName = "") {
|
||||
LOG_TRACE << "pathPattern:" << pathPattern;
|
||||
|
||||
/*
|
||||
auto binder = std::make_shared<internal::HttpBinder<FUNCTION> >(
|
||||
std::forward<FUNCTION>(function));
|
||||
|
||||
@ -449,8 +448,10 @@ public:
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
registerHttpController(
|
||||
pathPattern, binder, validMethods, filters, handlerName);
|
||||
*/
|
||||
|
||||
//registerHttpController(
|
||||
// pathPattern, binder, validMethods, filters, handlerName);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
@ -476,11 +477,13 @@ public:
|
||||
std::vector<internal::HttpConstraint>{},
|
||||
const std::string &handlerName = "") {
|
||||
LOG_TRACE << "regex:" << regExp;
|
||||
|
||||
/*
|
||||
internal::HttpBinderBasePtr binder;
|
||||
|
||||
binder = std::make_shared<internal::HttpBinder<FUNCTION> >(
|
||||
std::forward<FUNCTION>(function));
|
||||
|
||||
*/
|
||||
std::vector<HttpMethod> validMethods;
|
||||
std::vector<std::string> filters;
|
||||
for (auto const &filterOrMethod : filtersAndMethods) {
|
||||
@ -494,8 +497,8 @@ public:
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
registerHttpControllerViaRegex(
|
||||
regExp, binder, validMethods, filters, handlerName);
|
||||
// registerHttpControllerViaRegex(
|
||||
// regExp, binder, validMethods, filters, handlerName);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -548,8 +551,11 @@ public:
|
||||
"Controllers created and initialized "
|
||||
"automatically by drogon cannot be "
|
||||
"registered here");
|
||||
DrClassMap::setSingleInstance(ctrlPtr);
|
||||
|
||||
//DrClassMap::setSingleInstance(ctrlPtr);
|
||||
|
||||
T::initPathRouting();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -565,7 +571,7 @@ public:
|
||||
"Filters created and initialized "
|
||||
"automatically by drogon cannot be "
|
||||
"registered here");
|
||||
DrClassMap::setSingleInstance(filterPtr);
|
||||
//DrClassMap::setSingleInstance(filterPtr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1230,6 +1236,7 @@ public:
|
||||
virtual const ExceptionHandler &getExceptionHandler() const = 0;
|
||||
|
||||
private:
|
||||
/*
|
||||
virtual void registerHttpController(
|
||||
const std::string &pathPattern,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
@ -1241,7 +1248,7 @@ private:
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
const std::vector<HttpMethod> &validMethods,
|
||||
const std::vector<std::string> &filters,
|
||||
const std::string &handlerName) = 0;
|
||||
const std::string &handlerName) = 0;*/
|
||||
};
|
||||
|
||||
/// A wrapper of the instance() method
|
||||
|
@ -1,381 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @file HttpBinder.h
|
||||
* @author 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
|
||||
*
|
||||
*/
|
||||
|
||||
/// The classes in the file are internal tool classes. Do not include this
|
||||
/// file directly and use any of these classes directly.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/exports.h>
|
||||
#include <drogon/utils/FunctionTraits.h>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace drogon {
|
||||
namespace internal {
|
||||
// we only accept value type or const lreference type or right reference type as
|
||||
// the handle method parameters type
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits {
|
||||
static const bool isValid = true;
|
||||
};
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<T *> {
|
||||
static const bool isValid = false;
|
||||
};
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<T &> {
|
||||
static const bool isValid = false;
|
||||
};
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<T &&> {
|
||||
static const bool isValid = true;
|
||||
};
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<const T &&> {
|
||||
static const bool isValid = false;
|
||||
};
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<const T &> {
|
||||
static const bool isValid = true;
|
||||
};
|
||||
|
||||
class HttpBinderBase {
|
||||
public:
|
||||
virtual void handleHttpRequest(
|
||||
std::deque<std::string> &pathArguments,
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) = 0;
|
||||
virtual size_t paramCount() = 0;
|
||||
virtual const std::string &handlerName() const = 0;
|
||||
virtual ~HttpBinderBase() {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T &getControllerObj() {
|
||||
// Initialization of function-local statics is guaranteed to occur only once
|
||||
// even when
|
||||
// called from multiple threads, and may be more efficient than the
|
||||
// equivalent code using std::call_once.
|
||||
static T obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
DROGON_EXPORT void handleException(
|
||||
const std::exception &,
|
||||
const HttpRequestPtr &,
|
||||
std::function<void(const HttpResponsePtr &)> &&);
|
||||
|
||||
using HttpBinderBasePtr = std::shared_ptr<HttpBinderBase>;
|
||||
template <typename FUNCTION>
|
||||
class HttpBinder : public HttpBinderBase {
|
||||
public:
|
||||
using traits = FunctionTraits<FUNCTION>;
|
||||
using FunctionType = FUNCTION;
|
||||
void handleHttpRequest(
|
||||
std::deque<std::string> &pathArguments,
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) override {
|
||||
run(pathArguments, req, std::move(callback));
|
||||
}
|
||||
size_t paramCount() override {
|
||||
return traits::arity;
|
||||
}
|
||||
HttpBinder(FUNCTION &&func) :
|
||||
func_(std::forward<FUNCTION>(func)) {
|
||||
static_assert(traits::isHTTPFunction,
|
||||
"Your API handler function interface is wrong!");
|
||||
handlerName_ = DrClassMap::demangle(typeid(FUNCTION).name());
|
||||
}
|
||||
void test() {
|
||||
std::cout << "argument_count=" << argument_count << " "
|
||||
<< traits::isHTTPFunction << std::endl;
|
||||
}
|
||||
const std::string &handlerName() const override {
|
||||
return handlerName_;
|
||||
}
|
||||
template <bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass>
|
||||
typename std::enable_if<isDrObjectClass && isClassFunction, void>::type
|
||||
createHandlerInstance() {
|
||||
auto objPtr =
|
||||
DrClassMap::getSingleInstance<typename traits::class_type>();
|
||||
LOG_TRACE << "create handler class object: " << objPtr.get();
|
||||
}
|
||||
template <bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass>
|
||||
typename std::enable_if<!isDrObjectClass && isClassFunction, void>::type
|
||||
createHandlerInstance() {
|
||||
auto &obj = getControllerObj<typename traits::class_type>();
|
||||
LOG_TRACE << "create handler class object: " << &obj;
|
||||
}
|
||||
template <bool isClassFunction = traits::isClassFunction>
|
||||
typename std::enable_if<!isClassFunction, void>::type
|
||||
createHandlerInstance() {
|
||||
}
|
||||
|
||||
private:
|
||||
FUNCTION func_;
|
||||
template <std::size_t Index>
|
||||
using nth_argument_type = typename traits::template argument<Index>;
|
||||
|
||||
static const size_t argument_count = traits::arity;
|
||||
std::string handlerName_;
|
||||
|
||||
template <typename T>
|
||||
struct CanConvertFromStringStream {
|
||||
private:
|
||||
using yes = std::true_type;
|
||||
using no = std::false_type;
|
||||
|
||||
template <typename U>
|
||||
static auto test(U *p, std::stringstream &&ss)
|
||||
-> decltype((ss >> *p), yes());
|
||||
|
||||
template <typename>
|
||||
static no test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
std::is_same<decltype(test<T>(nullptr, std::stringstream())),
|
||||
yes>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<CanConvertFromStringStream<T>::value, void>::type
|
||||
getHandlerArgumentValue(T &value, std::string &&p) {
|
||||
if (!p.empty()) {
|
||||
std::stringstream ss(std::move(p));
|
||||
ss >> value;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!(CanConvertFromStringStream<T>::value), void>::type
|
||||
getHandlerArgumentValue(T &value, std::string &&p) {
|
||||
}
|
||||
|
||||
void getHandlerArgumentValue(std::string &value, std::string &&p) {
|
||||
value = std::move(p);
|
||||
}
|
||||
|
||||
void getHandlerArgumentValue(int &value, std::string &&p) {
|
||||
value = std::stoi(p);
|
||||
}
|
||||
|
||||
void getHandlerArgumentValue(long &value, std::string &&p) {
|
||||
value = std::stol(p);
|
||||
}
|
||||
|
||||
void getHandlerArgumentValue(long long &value, std::string &&p) {
|
||||
value = std::stoll(p);
|
||||
}
|
||||
|
||||
void getHandlerArgumentValue(unsigned long &value, std::string &&p) {
|
||||
value = std::stoul(p);
|
||||
}
|
||||
|
||||
void getHandlerArgumentValue(unsigned long long &value, std::string &&p) {
|
||||
value = std::stoull(p);
|
||||
}
|
||||
|
||||
void getHandlerArgumentValue(float &value, std::string &&p) {
|
||||
value = std::stof(p);
|
||||
}
|
||||
|
||||
void getHandlerArgumentValue(double &value, std::string &&p) {
|
||||
value = std::stod(p);
|
||||
}
|
||||
|
||||
void getHandlerArgumentValue(long double &value, std::string &&p) {
|
||||
value = std::stold(p);
|
||||
}
|
||||
|
||||
template <typename... Values, std::size_t Boundary = argument_count>
|
||||
typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
|
||||
std::deque<std::string> &pathArguments,
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
Values &&...values) {
|
||||
// Call this function recursively until parameter's count equals to the
|
||||
// count of target function parameters
|
||||
static_assert(
|
||||
BinderArgTypeTraits<nth_argument_type<sizeof...(Values)> >::isValid,
|
||||
"your handler argument type must be value type or const left "
|
||||
"reference type or right reference type");
|
||||
using ValueType =
|
||||
typename std::remove_cv<typename std::remove_reference<
|
||||
nth_argument_type<sizeof...(Values)> >::type>::type;
|
||||
ValueType value = ValueType();
|
||||
if (!pathArguments.empty()) {
|
||||
std::string v = std::move(pathArguments.front());
|
||||
pathArguments.pop_front();
|
||||
try {
|
||||
if (v.empty() == false)
|
||||
getHandlerArgumentValue(value, std::move(v));
|
||||
} catch (const std::exception &e) {
|
||||
handleException(e, req, std::move(callback));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
value = req->as<ValueType>();
|
||||
} catch (const std::exception &e) {
|
||||
handleException(e, req, std::move(callback));
|
||||
return;
|
||||
} catch (...) {
|
||||
LOG_ERROR << "Exception not derived from std::exception";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
run(pathArguments,
|
||||
req,
|
||||
std::move(callback),
|
||||
std::forward<Values>(values)...,
|
||||
std::move(value));
|
||||
}
|
||||
template <typename... Values,
|
||||
std::size_t Boundary = argument_count,
|
||||
bool isCoroutine = traits::isCoroutine>
|
||||
typename std::enable_if<(sizeof...(Values) == Boundary) && !isCoroutine,
|
||||
void>::type
|
||||
run(std::deque<std::string> &,
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
Values &&...values) {
|
||||
try {
|
||||
// Explcit copy because `callFunction` moves it
|
||||
auto cb = callback;
|
||||
callFunction(req, cb, std::move(values)...);
|
||||
} catch (const std::exception &except) {
|
||||
handleException(except, req, std::move(callback));
|
||||
} catch (...) {
|
||||
LOG_ERROR << "Exception not derived from std::exception";
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef __cpp_impl_coroutine
|
||||
template <typename... Values,
|
||||
std::size_t Boundary = argument_count,
|
||||
bool isCoroutine = traits::isCoroutine>
|
||||
typename std::enable_if<(sizeof...(Values) == Boundary) && isCoroutine,
|
||||
void>::type
|
||||
run(std::deque<std::string> &,
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
Values &&...values) {
|
||||
[this](HttpRequestPtr req,
|
||||
std::function<void(const HttpResponsePtr &)> callback,
|
||||
Values &&...values) -> AsyncTask {
|
||||
try {
|
||||
if constexpr (std::is_same_v<AsyncTask,
|
||||
typename traits::return_type>) {
|
||||
// Explcit copy because `callFunction` moves it
|
||||
auto cb = callback;
|
||||
callFunction(req, cb, std::move(values)...);
|
||||
} else if constexpr (std::is_same_v<Task<>,
|
||||
typename traits::return_type>) {
|
||||
// Explcit copy because `callFunction` moves it
|
||||
auto cb = callback;
|
||||
co_await callFunction(req, cb, std::move(values)...);
|
||||
} else if constexpr (std::is_same_v<Task<HttpResponsePtr>,
|
||||
typename traits::return_type>) {
|
||||
auto resp =
|
||||
co_await callFunction(req, std::move(values)...);
|
||||
callback(std::move(resp));
|
||||
}
|
||||
} catch (const std::exception &except) {
|
||||
handleException(except, req, std::move(callback));
|
||||
} catch (...) {
|
||||
LOG_ERROR << "Exception not derived from std::exception";
|
||||
}
|
||||
}(req, std::move(callback), std::move(values)...);
|
||||
}
|
||||
#endif
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass,
|
||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||
HttpRequestPtr>::value>
|
||||
typename std::enable_if<isClassFunction && !isDrObjectClass && isNormal,
|
||||
typename traits::return_type>::type
|
||||
callFunction(const HttpRequestPtr &req, Values &&...values) {
|
||||
static auto &obj = getControllerObj<typename traits::class_type>();
|
||||
return (obj.*func_)(req, std::move(values)...);
|
||||
}
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass,
|
||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||
HttpRequestPtr>::value>
|
||||
typename std::enable_if<isClassFunction && isDrObjectClass && isNormal,
|
||||
typename traits::return_type>::type
|
||||
callFunction(const HttpRequestPtr &req, Values &&...values) {
|
||||
static auto objPtr =
|
||||
DrClassMap::getSingleInstance<typename traits::class_type>();
|
||||
return (*objPtr.*func_)(req, std::move(values)...);
|
||||
}
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction,
|
||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||
HttpRequestPtr>::value>
|
||||
typename std::enable_if<!isClassFunction && isNormal,
|
||||
typename traits::return_type>::type
|
||||
callFunction(const HttpRequestPtr &req, Values &&...values) {
|
||||
return func_(req, std::move(values)...);
|
||||
}
|
||||
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass,
|
||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||
HttpRequestPtr>::value>
|
||||
typename std::enable_if<isClassFunction && !isDrObjectClass && !isNormal,
|
||||
typename traits::return_type>::type
|
||||
callFunction(const HttpRequestPtr &req, Values &&...values) {
|
||||
static auto &obj = getControllerObj<typename traits::class_type>();
|
||||
return (obj.*func_)((*req), std::move(values)...);
|
||||
}
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass,
|
||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||
HttpRequestPtr>::value>
|
||||
typename std::enable_if<isClassFunction && isDrObjectClass && !isNormal,
|
||||
typename traits::return_type>::type
|
||||
callFunction(const HttpRequestPtr &req, Values &&...values) {
|
||||
static auto objPtr =
|
||||
DrClassMap::getSingleInstance<typename traits::class_type>();
|
||||
return (*objPtr.*func_)((*req), std::move(values)...);
|
||||
}
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction,
|
||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||
HttpRequestPtr>::value>
|
||||
typename std::enable_if<!isClassFunction && !isNormal,
|
||||
typename traits::return_type>::type
|
||||
callFunction(const HttpRequestPtr &req, Values &&...values) {
|
||||
return func_((*req), std::move(values)...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace drogon
|
@ -14,7 +14,6 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "drogon/HttpBinder.h"
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <drogon/HttpTypes.h>
|
||||
|
@ -1,132 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* HttpController.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 <drogon/HttpAppFramework.h>
|
||||
#include <drogon/utils/HttpConstraint.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/// For more details on the class, see the wiki site (the 'HttpController'
|
||||
/// section)
|
||||
|
||||
#define METHOD_LIST_BEGIN \
|
||||
static void initPathRouting() {
|
||||
#define METHOD_ADD(method, pattern, ...) \
|
||||
registerMethod(&method, pattern, { __VA_ARGS__ }, true, #method)
|
||||
#define ADD_METHOD_TO(method, path_pattern, ...) \
|
||||
registerMethod(&method, path_pattern, { __VA_ARGS__ }, false, #method)
|
||||
#define ADD_METHOD_VIA_REGEX(method, regex, ...) \
|
||||
registerMethodViaRegex(&method, regex, { __VA_ARGS__ }, #method)
|
||||
#define METHOD_LIST_END \
|
||||
return; \
|
||||
}
|
||||
|
||||
namespace drogon {
|
||||
/**
|
||||
* @brief The base class for HTTP controllers.
|
||||
*
|
||||
*/
|
||||
class HttpControllerBase {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The reflection base class template for HTTP controllers
|
||||
*
|
||||
* @tparam T the type of the implementation class
|
||||
* @tparam AutoCreation The flag for automatically creating, user can set this
|
||||
* flag to false for classes that have nondefault constructors.
|
||||
*/
|
||||
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,
|
||||
const std::string &pattern,
|
||||
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||
std::vector<internal::HttpConstraint>{},
|
||||
bool classNameInPath = true,
|
||||
const std::string &handlerName = "") {
|
||||
if (classNameInPath) {
|
||||
std::string path = "/";
|
||||
path.append(HttpController<T>::classTypeName());
|
||||
LOG_TRACE << "classname:" << HttpController<T>::classTypeName();
|
||||
|
||||
// transform(path.begin(), path.end(), path.begin(), tolower);
|
||||
std::string::size_type pos;
|
||||
while ((pos = path.find("::")) != std::string::npos) {
|
||||
path.replace(pos, 2, "/");
|
||||
}
|
||||
if (pattern.empty() || pattern[0] == '/')
|
||||
app().registerHandler(path + pattern,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods,
|
||||
handlerName);
|
||||
else
|
||||
app().registerHandler(path + "/" + pattern,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods,
|
||||
handlerName);
|
||||
} else {
|
||||
std::string path = pattern;
|
||||
if (path.empty() || path[0] != '/') {
|
||||
path = "/" + path;
|
||||
}
|
||||
app().registerHandler(path,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods,
|
||||
handlerName);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FUNCTION>
|
||||
static void registerMethodViaRegex(
|
||||
FUNCTION &&function,
|
||||
const std::string ®Exp,
|
||||
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||
std::vector<internal::HttpConstraint>{},
|
||||
const std::string &handlerName = "") {
|
||||
app().registerHandlerViaRegex(regExp,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods,
|
||||
handlerName);
|
||||
}
|
||||
|
||||
private:
|
||||
class methodRegistrator {
|
||||
public:
|
||||
methodRegistrator() {
|
||||
if (AutoCreation)
|
||||
T::initPathRouting();
|
||||
}
|
||||
};
|
||||
// use static value to register controller method in framework before
|
||||
// main();
|
||||
static methodRegistrator registrator_;
|
||||
virtual void *touch() {
|
||||
return ®istrator_;
|
||||
}
|
||||
};
|
||||
template <typename T, bool AutoCreation>
|
||||
typename HttpController<T, AutoCreation>::methodRegistrator
|
||||
HttpController<T, AutoCreation>::registrator_;
|
||||
} // namespace drogon
|
@ -14,7 +14,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <drogon/drogon_callbacks.h>
|
||||
@ -25,7 +24,7 @@ namespace drogon {
|
||||
* @brief The abstract base class for filters
|
||||
* For more details on the class, see the wiki site (the 'Filter' section)
|
||||
*/
|
||||
class DROGON_EXPORT HttpFilterBase : public virtual DrObjectBase {
|
||||
class DROGON_EXPORT HttpFilterBase {
|
||||
public:
|
||||
/// This virtual function should be overrided in subclasses.
|
||||
/**
|
||||
@ -53,7 +52,7 @@ public:
|
||||
* flag to false for classes that have nondefault constructors.
|
||||
*/
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class HttpFilter : public DrObject<T>, public HttpFilterBase {
|
||||
class HttpFilter : public HttpFilterBase {
|
||||
public:
|
||||
static constexpr bool isAutoCreation{ AutoCreation };
|
||||
virtual ~HttpFilter() {
|
||||
|
@ -15,7 +15,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <drogon/Attribute.h>
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <drogon/HttpTypes.h>
|
||||
#include <drogon/Session.h>
|
||||
#include <drogon/UploadFile.h>
|
||||
@ -38,8 +37,8 @@ using HttpRequestPtr = std::shared_ptr<HttpRequest>;
|
||||
*/
|
||||
template <typename T>
|
||||
T fromRequest(const HttpRequest &req) {
|
||||
LOG_ERROR << "You must specialize the fromRequest template for the type of "
|
||||
<< DrClassMap::demangle(typeid(T).name());
|
||||
LOG_ERROR << "You must specialize the fromRequest template for the type of ";
|
||||
// << DrClassMap::demangle(typeid(T).name());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -50,8 +49,8 @@ T fromRequest(const HttpRequest &req) {
|
||||
*/
|
||||
template <typename T>
|
||||
HttpRequestPtr toRequest(T &&) {
|
||||
LOG_ERROR << "You must specialize the toRequest template for the type of "
|
||||
<< DrClassMap::demangle(typeid(T).name());
|
||||
LOG_ERROR << "You must specialize the toRequest template for the type of ";
|
||||
// << DrClassMap::demangle(typeid(T).name());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <drogon/Cookie.h>
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <drogon/HttpTypes.h>
|
||||
#include <drogon/HttpViewData.h>
|
||||
#include <drogon/exports.h>
|
||||
@ -35,8 +34,8 @@ using HttpResponsePtr = std::shared_ptr<HttpResponse>;
|
||||
template <typename T>
|
||||
T fromResponse(const HttpResponse &resp) {
|
||||
LOG_ERROR
|
||||
<< "You must specialize the fromResponse template for the type of "
|
||||
<< DrClassMap::demangle(typeid(T).name());
|
||||
<< "You must specialize the fromResponse template for the type of ";
|
||||
//<< DrClassMap::demangle(typeid(T).name());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -47,8 +46,8 @@ T fromResponse(const HttpResponse &resp) {
|
||||
*/
|
||||
template <typename T>
|
||||
HttpResponsePtr toResponse(T &&) {
|
||||
LOG_ERROR << "You must specialize the toResponse template for the type of "
|
||||
<< DrClassMap::demangle(typeid(T).name());
|
||||
LOG_ERROR << "You must specialize the toResponse template for the type of ";
|
||||
// << DrClassMap::demangle(typeid(T).name());
|
||||
exit(1);
|
||||
}
|
||||
template <>
|
||||
|
@ -1,95 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* HttpSimpleController.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 <drogon/HttpAppFramework.h>
|
||||
#include <drogon/utils/HttpConstraint.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#define PATH_LIST_BEGIN \
|
||||
static void initPathRouting() {
|
||||
#define PATH_ADD(path, ...) registerSelf__(path, { __VA_ARGS__ });
|
||||
#define PATH_LIST_END }
|
||||
namespace drogon {
|
||||
/**
|
||||
* @brief The abstract base class for HTTP simple controllers.
|
||||
*
|
||||
*/
|
||||
class HttpSimpleControllerBase : public virtual DrObjectBase {
|
||||
public:
|
||||
/**
|
||||
* @brief The function is called when a HTTP request is routed to the
|
||||
* controller.
|
||||
*
|
||||
* @param req The HTTP request.
|
||||
* @param callback The callback via which a response is returned.
|
||||
*/
|
||||
virtual void asyncHandleHttpRequest(
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) = 0;
|
||||
virtual ~HttpSimpleControllerBase() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The reflection base class template for HTTP simple controllers
|
||||
*
|
||||
* @tparam T The type of the implementation class
|
||||
* @tparam AutoCreation The flag for automatically creating, user can set this
|
||||
* flag to false for classes that have nondefault constructors.
|
||||
*/
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class HttpSimpleController : public DrObject<T>, public HttpSimpleControllerBase {
|
||||
public:
|
||||
static const bool isAutoCreation = AutoCreation;
|
||||
virtual ~HttpSimpleController() {
|
||||
}
|
||||
|
||||
protected:
|
||||
HttpSimpleController() {
|
||||
}
|
||||
static void registerSelf__(
|
||||
const std::string &path,
|
||||
const std::vector<internal::HttpConstraint> &filtersAndMethods) {
|
||||
LOG_TRACE << "register simple controller("
|
||||
<< HttpSimpleController<T>::classTypeName()
|
||||
<< ") on path:" << path;
|
||||
app().registerHttpSimpleController(
|
||||
path, HttpSimpleController<T>::classTypeName(), filtersAndMethods);
|
||||
}
|
||||
|
||||
private:
|
||||
class pathRegistrator {
|
||||
public:
|
||||
pathRegistrator() {
|
||||
if (AutoCreation) {
|
||||
T::initPathRouting();
|
||||
}
|
||||
}
|
||||
};
|
||||
friend pathRegistrator;
|
||||
static pathRegistrator registrator_;
|
||||
virtual void *touch() {
|
||||
return ®istrator_;
|
||||
}
|
||||
};
|
||||
template <typename T, bool AutoCreation>
|
||||
typename HttpSimpleController<T, AutoCreation>::pathRegistrator
|
||||
HttpSimpleController<T, AutoCreation>::registrator_;
|
||||
|
||||
} // namespace drogon
|
@ -1,31 +0,0 @@
|
||||
// this file is generated by program automatically,don't modify it!
|
||||
|
||||
/**
|
||||
*
|
||||
* @file NotFound.h
|
||||
* @author 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/DrTemplate.h>
|
||||
#include <drogon/exports.h>
|
||||
namespace drogon {
|
||||
/**
|
||||
* @brief This class is used by the drogon to generate the 404 page. Users don't
|
||||
* use this class directly.
|
||||
*/
|
||||
class DROGON_EXPORT NotFound final : public drogon::DrTemplate<NotFound> {
|
||||
public:
|
||||
NotFound() {
|
||||
}
|
||||
virtual std::string genText(const drogon::HttpViewData &) override;
|
||||
};
|
||||
} // namespace drogon
|
@ -1,104 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* WebSocketController.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 <drogon/HttpAppFramework.h>
|
||||
#include <drogon/HttpTypes.h>
|
||||
#include <drogon/WebSocketConnection.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define WS_PATH_LIST_BEGIN \
|
||||
static void initPathRouting() {
|
||||
#define WS_PATH_ADD(path, ...) registerSelf__(path, { __VA_ARGS__ });
|
||||
#define WS_PATH_LIST_END }
|
||||
|
||||
namespace drogon {
|
||||
/**
|
||||
* @brief The abstract base class for WebSocket controllers.
|
||||
*
|
||||
*/
|
||||
class WebSocketControllerBase : public virtual DrObjectBase {
|
||||
public:
|
||||
// This function is called when a new message is received
|
||||
virtual void handleNewMessage(const WebSocketConnectionPtr &,
|
||||
std::string &&,
|
||||
const WebSocketMessageType &) = 0;
|
||||
|
||||
// This function is called after a new connection of WebSocket is
|
||||
// established.
|
||||
virtual void handleNewConnection(const HttpRequestPtr &,
|
||||
const WebSocketConnectionPtr &) = 0;
|
||||
|
||||
// This function is called after a WebSocket connection is closed
|
||||
virtual void handleConnectionClosed(const WebSocketConnectionPtr &) = 0;
|
||||
|
||||
virtual ~WebSocketControllerBase() {
|
||||
}
|
||||
};
|
||||
|
||||
using WebSocketControllerBasePtr = std::shared_ptr<WebSocketControllerBase>;
|
||||
|
||||
/**
|
||||
* @brief The reflection base class template for WebSocket controllers
|
||||
*
|
||||
* @tparam T the type of the implementation class
|
||||
* @tparam AutoCreation The flag for automatically creating, user can set this
|
||||
* flag to false for classes that have nondefault constructors.
|
||||
*/
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class WebSocketController : public DrObject<T>, public WebSocketControllerBase {
|
||||
public:
|
||||
static const bool isAutoCreation = AutoCreation;
|
||||
virtual ~WebSocketController() {
|
||||
}
|
||||
|
||||
protected:
|
||||
WebSocketController() {
|
||||
}
|
||||
static void registerSelf__(
|
||||
const std::string &path,
|
||||
const std::vector<internal::HttpConstraint> &filtersAndMethods) {
|
||||
LOG_TRACE << "register websocket controller("
|
||||
<< WebSocketController<T>::classTypeName()
|
||||
<< ") on path:" << path;
|
||||
app().registerWebSocketController(
|
||||
path, WebSocketController<T>::classTypeName(), filtersAndMethods);
|
||||
}
|
||||
|
||||
private:
|
||||
class pathRegistrator {
|
||||
public:
|
||||
pathRegistrator() {
|
||||
if (AutoCreation) {
|
||||
T::initPathRouting();
|
||||
}
|
||||
}
|
||||
};
|
||||
friend pathRegistrator;
|
||||
static pathRegistrator registrator_;
|
||||
virtual void *touch() {
|
||||
return ®istrator_;
|
||||
}
|
||||
};
|
||||
template <typename T, bool AutoCreation>
|
||||
typename WebSocketController<T, AutoCreation>::pathRegistrator
|
||||
WebSocketController<T, AutoCreation>::registrator_;
|
||||
|
||||
} // namespace drogon
|
@ -23,8 +23,6 @@
|
||||
#include <drogon/Cookie.h>
|
||||
#include <drogon/HttpAppFramework.h>
|
||||
#include <drogon/HttpClient.h>
|
||||
#include <drogon/HttpController.h>
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
#include <drogon/IOThreadStorage.h>
|
||||
#include <drogon/MultiPart.h>
|
||||
#include <drogon/Session.h>
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <json/json.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
@ -30,8 +29,7 @@ enum class PluginStatus {
|
||||
* @brief The abstract base class for plugins.
|
||||
*
|
||||
*/
|
||||
class DROGON_EXPORT PluginBase : public virtual DrObjectBase,
|
||||
public trantor::NonCopyable {
|
||||
class PluginBase : public trantor::NonCopyable {
|
||||
public:
|
||||
/// This method must be called by drogon.
|
||||
void initialize() {
|
||||
@ -105,7 +103,7 @@ struct IsPlugin {
|
||||
* @tparam T The type of the implementation plugin classes.
|
||||
*/
|
||||
template <typename T>
|
||||
class Plugin : public PluginBase, public DrObject<T> {
|
||||
class Plugin : public PluginBase {
|
||||
public:
|
||||
virtual ~Plugin() {
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
@ -1,89 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* DrClassMap.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 <drogon/DrClassMap.h>
|
||||
#include <drogon/DrObject.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
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) {
|
||||
LOG_TRACE << "Register class:" << className;
|
||||
getMap().insert(std::make_pair(className, func));
|
||||
}
|
||||
|
||||
DrObjectBase *DrClassMap::newObject(const std::string &className) {
|
||||
auto iter = getMap().find(className);
|
||||
if (iter != getMap().end()) {
|
||||
return iter->second();
|
||||
} else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::shared_ptr<DrObjectBase> &DrClassMap::getSingleInstance(
|
||||
const std::string &className) {
|
||||
auto &mtx = internal::getMapMutex();
|
||||
auto &singleInstanceMap = internal::getObjsMap();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
auto iter = singleInstanceMap.find(className);
|
||||
if (iter != singleInstanceMap.end())
|
||||
return iter->second;
|
||||
}
|
||||
auto newObj = std::shared_ptr<DrObjectBase>(newObject(className));
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
auto ret = singleInstanceMap.insert(
|
||||
std::make_pair(className, std::move(newObj)));
|
||||
return ret.first->second;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
for (auto const &iter : getMap()) {
|
||||
ret.push_back(iter.first);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, DrAllocFunc> &DrClassMap::getMap() {
|
||||
static std::unordered_map<std::string, DrAllocFunc> map;
|
||||
return map;
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @file DrTemplateBase.cc
|
||||
* @author 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 <drogon/DrClassMap.h>
|
||||
#include <drogon/DrTemplateBase.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
std::shared_ptr<DrTemplateBase> DrTemplateBase::newTemplate(
|
||||
const std::string &templateName) {
|
||||
LOG_TRACE << "http view name=" << templateName;
|
||||
auto l = templateName.length();
|
||||
if (l >= 4 && templateName[l - 4] == '.' && templateName[l - 3] == 'c' &&
|
||||
templateName[l - 2] == 's' && templateName[l - 1] == 'p') {
|
||||
std::string::size_type pos = 0;
|
||||
std::string newName;
|
||||
newName.reserve(templateName.size());
|
||||
if (templateName[0] == '/' || templateName[0] == '\\') {
|
||||
pos = 1;
|
||||
} else if (templateName[0] == '.' &&
|
||||
(templateName[1] == '/' || templateName[1] == '\\')) {
|
||||
pos = 2;
|
||||
}
|
||||
while (pos < l - 4) {
|
||||
if (templateName[pos] == '/' || templateName[pos] == '\\') {
|
||||
newName.append("::");
|
||||
} else {
|
||||
newName.append(1, templateName[pos]);
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
return std::shared_ptr<DrTemplateBase>(dynamic_cast<DrTemplateBase *>(
|
||||
drogon::DrClassMap::newObject(newName)));
|
||||
} else {
|
||||
return std::shared_ptr<DrTemplateBase>(dynamic_cast<DrTemplateBase *>(
|
||||
drogon::DrClassMap::newObject(templateName)));
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @file FiltersFunction.cc
|
||||
* @author 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 "FiltersFunction.h"
|
||||
#include "HttpAppFrameworkImpl.h"
|
||||
#include "HttpRequestImpl.h"
|
||||
#include "HttpResponseImpl.h"
|
||||
#include <drogon/HttpFilter.h>
|
||||
|
||||
#include <queue>
|
||||
|
||||
namespace drogon {
|
||||
namespace filters_function {
|
||||
static void doFilterChains(
|
||||
const std::vector<std::shared_ptr<HttpFilterBase> > &filters,
|
||||
size_t index,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)> >
|
||||
&callbackPtr,
|
||||
std::function<void()> &&missCallback) {
|
||||
if (index < filters.size()) {
|
||||
auto &filter = filters[index];
|
||||
filter->doFilter(
|
||||
req,
|
||||
[req, callbackPtr](const HttpResponsePtr &res) {
|
||||
HttpAppFrameworkImpl::instance().callCallback(req,
|
||||
res,
|
||||
*callbackPtr);
|
||||
},
|
||||
[index,
|
||||
req,
|
||||
callbackPtr,
|
||||
&filters,
|
||||
missCallback = std::move(missCallback)]() mutable {
|
||||
doFilterChains(filters,
|
||||
index + 1,
|
||||
req,
|
||||
callbackPtr,
|
||||
std::move(missCallback));
|
||||
});
|
||||
} else {
|
||||
missCallback();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<HttpFilterBase> > createFilters(
|
||||
const std::vector<std::string> &filterNames) {
|
||||
std::vector<std::shared_ptr<HttpFilterBase> > filters;
|
||||
for (auto const &filter : filterNames) {
|
||||
auto object_ = DrClassMap::getSingleInstance(filter);
|
||||
auto filter_ = std::dynamic_pointer_cast<HttpFilterBase>(object_);
|
||||
if (filter_)
|
||||
filters.push_back(filter_);
|
||||
else {
|
||||
LOG_ERROR << "filter " << filter << " not found";
|
||||
}
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
void doFilters(
|
||||
const std::vector<std::shared_ptr<HttpFilterBase> > &filters,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)> >
|
||||
&callbackPtr,
|
||||
std::function<void()> &&missCallback) {
|
||||
doFilterChains(filters, 0, req, callbackPtr, std::move(missCallback));
|
||||
}
|
||||
|
||||
} // namespace filters_function
|
||||
} // namespace drogon
|
@ -1,34 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* FiltersFunction.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 "impl_forwards.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace drogon {
|
||||
namespace filters_function {
|
||||
std::vector<std::shared_ptr<HttpFilterBase> > createFilters(
|
||||
const std::vector<std::string> &filterNames);
|
||||
void doFilters(
|
||||
const std::vector<std::shared_ptr<HttpFilterBase> > &filters,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)> >
|
||||
&callbackPtr,
|
||||
std::function<void()> &&missCallback);
|
||||
|
||||
} // namespace filters_function
|
||||
} // namespace drogon
|
@ -16,11 +16,9 @@
|
||||
#include "AOPAdvice.h"
|
||||
#include "ConfigLoader.h"
|
||||
#include "HttpClientImpl.h"
|
||||
#include "HttpControllersRouter.h"
|
||||
#include "HttpRequestImpl.h"
|
||||
#include "HttpResponseImpl.h"
|
||||
#include "HttpServer.h"
|
||||
#include "HttpSimpleControllersRouter.h"
|
||||
#include "ListenerManager.h"
|
||||
#include "PluginsManager.h"
|
||||
#include "SessionManager.h"
|
||||
@ -29,7 +27,6 @@
|
||||
#include "WebSocketConnectionImpl.h"
|
||||
#include "WebsocketControllersRouter.h"
|
||||
#include <drogon/CacheMap.h>
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <drogon/HttpTypes.h>
|
||||
@ -65,6 +62,7 @@ using namespace std::placeholders;
|
||||
|
||||
HttpAppFrameworkImpl::HttpAppFrameworkImpl() :
|
||||
staticFileRouterPtr_(new StaticFileRouter{}),
|
||||
/*
|
||||
httpCtrlsRouterPtr_(new HttpControllersRouter(*staticFileRouterPtr_,
|
||||
postRoutingAdvices_,
|
||||
postRoutingObservers_,
|
||||
@ -77,7 +75,7 @@ HttpAppFrameworkImpl::HttpAppFrameworkImpl() :
|
||||
postRoutingObservers_,
|
||||
preHandlingAdvices_,
|
||||
preHandlingObservers_,
|
||||
postHandlingAdvices_)),
|
||||
postHandlingAdvices_)),*/
|
||||
websockCtrlsRouterPtr_(
|
||||
new WebsocketControllersRouter(postRoutingAdvices_,
|
||||
postRoutingObservers_)),
|
||||
@ -256,12 +254,13 @@ HttpAppFramework &HttpAppFrameworkImpl::registerHttpSimpleController(
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &filtersAndMethods) {
|
||||
assert(!running_);
|
||||
httpSimpleCtrlsRouterPtr_->registerHttpSimpleController(pathName,
|
||||
ctrlName,
|
||||
filtersAndMethods);
|
||||
|
||||
//httpSimpleCtrlsRouterPtr_->registerHttpSimpleController(pathName, ctrlName, filtersAndMethods);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
void HttpAppFrameworkImpl::registerHttpController(
|
||||
const std::string &pathPattern,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
@ -287,6 +286,7 @@ void HttpAppFrameworkImpl::registerHttpControllerViaRegex(
|
||||
httpCtrlsRouterPtr_->addHttpRegex(
|
||||
regExp, binder, validMethods, filters, handlerName);
|
||||
}
|
||||
*/
|
||||
|
||||
HttpAppFramework &HttpAppFrameworkImpl::setThreadNum(size_t threadNum) {
|
||||
if (threadNum == 0) {
|
||||
@ -448,11 +448,13 @@ void HttpAppFrameworkImpl::run() {
|
||||
}
|
||||
asyncFileLogger.setFileName(baseName, ".log", logPath_);
|
||||
asyncFileLogger.startLogging();
|
||||
|
||||
trantor::Logger::setOutputFunction(
|
||||
[&](const char *msg, const uint64_t len) {
|
||||
asyncFileLogger.output(msg, len);
|
||||
},
|
||||
[&]() { asyncFileLogger.flush(); });
|
||||
|
||||
asyncFileLogger.setFileSizeLimit(logfileSize_);
|
||||
}
|
||||
}
|
||||
@ -500,13 +502,15 @@ void HttpAppFrameworkImpl::run() {
|
||||
pluginsManagerPtr_->initializeAllPlugins(pluginConfig,
|
||||
[](PluginBase *plugin) {
|
||||
LOG_TRACE
|
||||
<< "new plugin:"
|
||||
<< plugin->className();
|
||||
<< "new plugin:";
|
||||
// << plugin->className();
|
||||
// TODO: new plugin
|
||||
});
|
||||
}
|
||||
httpCtrlsRouterPtr_->init(ioLoops);
|
||||
httpSimpleCtrlsRouterPtr_->init(ioLoops);
|
||||
|
||||
//httpCtrlsRouterPtr_->init(ioLoops);
|
||||
//httpSimpleCtrlsRouterPtr_->init(ioLoops);
|
||||
|
||||
staticFileRouterPtr_->init(ioLoops);
|
||||
websockCtrlsRouterPtr_->init();
|
||||
getLoop()->queueInLoop([this]() {
|
||||
@ -634,12 +638,13 @@ void HttpAppFrameworkImpl::onNewWebsockRequest(
|
||||
|
||||
std::vector<std::tuple<std::string, HttpMethod, std::string> >
|
||||
HttpAppFrameworkImpl::getHandlersInfo() const {
|
||||
auto ret = httpSimpleCtrlsRouterPtr_->getHandlersInfo();
|
||||
//auto ret = httpSimpleCtrlsRouterPtr_->getHandlersInfo();
|
||||
/*
|
||||
auto v = httpCtrlsRouterPtr_->getHandlersInfo();
|
||||
ret.insert(ret.end(), v.begin(), v.end());
|
||||
v = websockCtrlsRouterPtr_->getHandlersInfo();
|
||||
ret.insert(ret.end(), v.begin(), v.end());
|
||||
return ret;
|
||||
ret.insert(ret.end(), v.begin(), v.end());*/
|
||||
auto v = websockCtrlsRouterPtr_->getHandlersInfo();
|
||||
//v.insert(ret.end(), v.begin(), v.end());
|
||||
return v;
|
||||
}
|
||||
void HttpAppFrameworkImpl::callCallback(
|
||||
const HttpRequestImplPtr &req,
|
||||
@ -709,6 +714,8 @@ void HttpAppFrameworkImpl::onAsyncRequest(
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
findSessionForRequest(req);
|
||||
// Route to controller
|
||||
if (!preRoutingObservers_.empty()) {
|
||||
@ -733,7 +740,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(
|
||||
[this, callbackPtr, req]() {
|
||||
httpSimpleCtrlsRouterPtr_->route(req, std::move(*callbackPtr));
|
||||
});
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
trantor::EventLoop *HttpAppFrameworkImpl::getLoop() const {
|
||||
|
@ -440,6 +440,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
void registerHttpController(const std::string &pathPattern,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
const std::vector<HttpMethod> &validMethods,
|
||||
@ -451,6 +452,8 @@ private:
|
||||
const std::vector<HttpMethod> &validMethods,
|
||||
const std::vector<std::string> &filters,
|
||||
const std::string &handlerName) override;
|
||||
*/
|
||||
|
||||
void onAsyncRequest(
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
@ -472,9 +475,9 @@ private:
|
||||
"\r\n" };
|
||||
|
||||
const std::unique_ptr<StaticFileRouter> staticFileRouterPtr_;
|
||||
const std::unique_ptr<HttpControllersRouter> httpCtrlsRouterPtr_;
|
||||
const std::unique_ptr<HttpSimpleControllersRouter>
|
||||
httpSimpleCtrlsRouterPtr_;
|
||||
//const std::unique_ptr<HttpControllersRouter> httpCtrlsRouterPtr_;
|
||||
//const std::unique_ptr<HttpSimpleControllersRouter>
|
||||
// httpSimpleCtrlsRouterPtr_;
|
||||
const std::unique_ptr<WebsocketControllersRouter> websockCtrlsRouterPtr_;
|
||||
|
||||
const std::unique_ptr<ListenerManager> listenerManagerPtr_;
|
||||
|
@ -1,26 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* HttpBinder.h
|
||||
* Martin Chang
|
||||
*
|
||||
* Copyright 2021, Martin Chang. 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 <drogon/HttpAppFramework.h>
|
||||
#include <drogon/HttpBinder.h>
|
||||
|
||||
namespace drogon {
|
||||
namespace internal {
|
||||
void handleException(const std::exception &e,
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
app().getExceptionHandler()(e, req, std::move(callback));
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace drogon
|
@ -1,682 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @file HttpControllersRouter.cc
|
||||
* @author 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 "HttpControllersRouter.h"
|
||||
#include "AOPAdvice.h"
|
||||
#include "FiltersFunction.h"
|
||||
#include "HttpAppFrameworkImpl.h"
|
||||
#include "HttpRequestImpl.h"
|
||||
#include "HttpResponseImpl.h"
|
||||
#include "StaticFileRouter.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <deque>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
void HttpControllersRouter::doWhenNoHandlerFound(
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
if (req->path() == "/" &&
|
||||
!HttpAppFrameworkImpl::instance().getHomePage().empty()) {
|
||||
req->setPath("/" + HttpAppFrameworkImpl::instance().getHomePage());
|
||||
// Just call the fileRouter_.route instead of forwarding. so comment out
|
||||
// those sentences.
|
||||
// HttpAppFrameworkImpl::instance().forward(req, std::move(callback));
|
||||
// return;
|
||||
}
|
||||
fileRouter_.route(req, std::move(callback));
|
||||
}
|
||||
|
||||
void HttpControllersRouter::init(
|
||||
const std::vector<trantor::EventLoop *> & /*ioLoops*/) {
|
||||
auto initFilters = [](auto &binders) {
|
||||
for (auto &binder : binders) {
|
||||
if (binder) {
|
||||
binder->filters_ =
|
||||
filters_function::createFilters(binder->filterNames_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (auto &router : ctrlVector_) {
|
||||
router.regex_ = std::regex(router.pathParameterPattern_,
|
||||
std::regex_constants::icase);
|
||||
initFilters(router.binders_);
|
||||
}
|
||||
|
||||
for (auto &p : ctrlMap_) {
|
||||
auto &router = p.second;
|
||||
router.regex_ = std::regex(router.pathParameterPattern_,
|
||||
std::regex_constants::icase);
|
||||
initFilters(router.binders_);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::tuple<std::string, HttpMethod, std::string> >
|
||||
HttpControllersRouter::getHandlersInfo() const {
|
||||
std::vector<std::tuple<std::string, HttpMethod, std::string> > ret;
|
||||
auto gatherInfo = [&](const auto &item) {
|
||||
for (size_t i = 0; i < Invalid; ++i) {
|
||||
if (item.binders_[i]) {
|
||||
auto description =
|
||||
item.binders_[i]->handlerName_.empty() ? std::string("Handler: ") +
|
||||
item.binders_[i]->binderPtr_->handlerName() :
|
||||
std::string("HttpController: ") +
|
||||
item.binders_[i]->handlerName_;
|
||||
auto info = std::tuple<std::string, HttpMethod, std::string>(
|
||||
item.pathPattern_, (HttpMethod)i, std::move(description));
|
||||
ret.emplace_back(std::move(info));
|
||||
}
|
||||
}
|
||||
};
|
||||
for (auto &item : ctrlVector_) {
|
||||
gatherInfo(item);
|
||||
}
|
||||
for (auto &data : ctrlMap_) {
|
||||
gatherInfo(data.second);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HttpControllersRouter::addHttpRegex(
|
||||
const std::string ®Exp,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
const std::vector<HttpMethod> &validMethods,
|
||||
const std::vector<std::string> &filters,
|
||||
const std::string &handlerName) {
|
||||
auto binderInfo = std::make_shared<CtrlBinder>();
|
||||
binderInfo->filterNames_ = filters;
|
||||
binderInfo->handlerName_ = handlerName;
|
||||
binderInfo->binderPtr_ = binder;
|
||||
drogon::app().getLoop()->queueInLoop([binderInfo]() {
|
||||
// Recreate this with the correct number of threads.
|
||||
binderInfo->responseCache_ = IOThreadStorage<HttpResponsePtr>();
|
||||
});
|
||||
{
|
||||
for (auto &router : ctrlVector_) {
|
||||
if (router.pathParameterPattern_ == regExp) {
|
||||
if (!validMethods.empty()) {
|
||||
for (auto const &method : validMethods) {
|
||||
router.binders_[method] = binderInfo;
|
||||
if (method == Options)
|
||||
binderInfo->isCORS_ = true;
|
||||
}
|
||||
} else {
|
||||
binderInfo->isCORS_ = true;
|
||||
for (int i = 0; i < Invalid; ++i)
|
||||
router.binders_[i] = binderInfo;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
struct HttpControllerRouterItem router;
|
||||
router.pathParameterPattern_ = regExp;
|
||||
router.pathPattern_ = regExp;
|
||||
if (!validMethods.empty()) {
|
||||
for (auto const &method : validMethods) {
|
||||
router.binders_[method] = binderInfo;
|
||||
if (method == Options)
|
||||
binderInfo->isCORS_ = true;
|
||||
}
|
||||
} else {
|
||||
binderInfo->isCORS_ = true;
|
||||
for (int i = 0; i < Invalid; ++i)
|
||||
router.binders_[i] = binderInfo;
|
||||
}
|
||||
ctrlVector_.push_back(std::move(router));
|
||||
}
|
||||
void HttpControllersRouter::addHttpPath(
|
||||
const std::string &path,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
const std::vector<HttpMethod> &validMethods,
|
||||
const std::vector<std::string> &filters,
|
||||
const std::string &handlerName) {
|
||||
// Path is like /api/v1/service/method/{1}/{2}/xxx...
|
||||
std::vector<size_t> places;
|
||||
std::string tmpPath = path;
|
||||
std::string paras;
|
||||
static const std::regex regex("\\{([^/]*)\\}");
|
||||
std::smatch results;
|
||||
auto pos = tmpPath.find('?');
|
||||
if (pos != std::string::npos) {
|
||||
paras = tmpPath.substr(pos + 1);
|
||||
tmpPath = tmpPath.substr(0, pos);
|
||||
}
|
||||
std::string originPath = tmpPath;
|
||||
size_t placeIndex = 1;
|
||||
while (std::regex_search(tmpPath, results, regex)) {
|
||||
if (results.size() > 1) {
|
||||
auto result = results[1].str();
|
||||
if (!result.empty() &&
|
||||
std::all_of(result.begin(), result.end(), [](const char c) {
|
||||
return std::isdigit(c);
|
||||
})) {
|
||||
auto place = (size_t)std::stoi(result);
|
||||
if (place > binder->paramCount() || place == 0) {
|
||||
LOG_ERROR << "Parameter placeholder(value=" << place
|
||||
<< ") out of range (1 to " << binder->paramCount()
|
||||
<< ")";
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
if (!std::all_of(places.begin(),
|
||||
places.end(),
|
||||
[place](size_t i) { return i != place; })) {
|
||||
LOG_ERROR << "Parameter placeholders are duplicated: index="
|
||||
<< place;
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
places.push_back(place);
|
||||
} else {
|
||||
static const std::regex regNumberAndName("([0-9]+):.*");
|
||||
std::smatch regexResult;
|
||||
if (std::regex_match(result, regexResult, regNumberAndName)) {
|
||||
assert(regexResult.size() == 2 && regexResult[1].matched);
|
||||
auto num = regexResult[1].str();
|
||||
auto place = (size_t)std::stoi(num);
|
||||
if (place > binder->paramCount() || place == 0) {
|
||||
LOG_ERROR << "Parameter placeholder(value=" << place
|
||||
<< ") out of range (1 to "
|
||||
<< binder->paramCount() << ")";
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
if (!std::all_of(places.begin(),
|
||||
places.end(),
|
||||
[place](size_t i) { return i != place; })) {
|
||||
LOG_ERROR
|
||||
<< "Parameter placeholders are duplicated: index="
|
||||
<< place;
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
places.push_back(place);
|
||||
} else {
|
||||
if (!std::all_of(places.begin(),
|
||||
places.end(),
|
||||
[placeIndex](size_t i) {
|
||||
return i != placeIndex;
|
||||
})) {
|
||||
LOG_ERROR
|
||||
<< "Parameter placeholders are duplicated: index="
|
||||
<< placeIndex;
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
places.push_back(placeIndex);
|
||||
}
|
||||
}
|
||||
++placeIndex;
|
||||
}
|
||||
tmpPath = results.suffix();
|
||||
}
|
||||
std::vector<std::pair<std::string, size_t> > parametersPlaces;
|
||||
if (!paras.empty()) {
|
||||
static const std::regex pregex("([^&]*)=\\{([^&]*)\\}&*");
|
||||
while (std::regex_search(paras, results, pregex)) {
|
||||
if (results.size() > 2) {
|
||||
auto result = results[2].str();
|
||||
if (!result.empty() &&
|
||||
std::all_of(result.begin(), result.end(), [](const char c) {
|
||||
return std::isdigit(c);
|
||||
})) {
|
||||
auto place = (size_t)std::stoi(result);
|
||||
if (place > binder->paramCount() || place == 0) {
|
||||
LOG_ERROR << "Parameter placeholder(value=" << place
|
||||
<< ") out of range (1 to "
|
||||
<< binder->paramCount() << ")";
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
if (!std::all_of(places.begin(),
|
||||
places.end(),
|
||||
[place](size_t i) {
|
||||
return i != place;
|
||||
}) ||
|
||||
!all_of(parametersPlaces.begin(),
|
||||
parametersPlaces.end(),
|
||||
[place](const std::pair<std::string, size_t>
|
||||
&item) {
|
||||
return item.second != place;
|
||||
})) {
|
||||
LOG_ERROR << "Parameter placeholders are "
|
||||
"duplicated: index="
|
||||
<< place;
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
parametersPlaces.emplace_back(results[1].str(), place);
|
||||
} else {
|
||||
std::regex regNumberAndName("([0-9]+):.*");
|
||||
std::smatch regexResult;
|
||||
if (std::regex_match(result, regexResult, regNumberAndName)) {
|
||||
assert(regexResult.size() == 2 &&
|
||||
regexResult[1].matched);
|
||||
auto num = regexResult[1].str();
|
||||
auto place = (size_t)std::stoi(num);
|
||||
if (place > binder->paramCount() || place == 0) {
|
||||
LOG_ERROR << "Parameter placeholder(value=" << place
|
||||
<< ") out of range (1 to "
|
||||
<< binder->paramCount() << ")";
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
if (!std::all_of(places.begin(),
|
||||
places.end(),
|
||||
[place](size_t i) {
|
||||
return i != place;
|
||||
}) ||
|
||||
!all_of(parametersPlaces.begin(),
|
||||
parametersPlaces.end(),
|
||||
[place](const std::pair<std::string, size_t>
|
||||
&item) {
|
||||
return item.second != place;
|
||||
})) {
|
||||
LOG_ERROR << "Parameter placeholders are "
|
||||
"duplicated: index="
|
||||
<< place;
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
parametersPlaces.emplace_back(results[1].str(), place);
|
||||
} else {
|
||||
if (!std::all_of(places.begin(),
|
||||
places.end(),
|
||||
[placeIndex](size_t i) {
|
||||
return i != placeIndex;
|
||||
}) ||
|
||||
!all_of(parametersPlaces.begin(),
|
||||
parametersPlaces.end(),
|
||||
[placeIndex](
|
||||
const std::pair<std::string, size_t>
|
||||
&item) {
|
||||
return item.second != placeIndex;
|
||||
})) {
|
||||
LOG_ERROR << "Parameter placeholders are "
|
||||
"duplicated: index="
|
||||
<< placeIndex;
|
||||
LOG_ERROR << "Path pattern: " << path;
|
||||
exit(1);
|
||||
}
|
||||
parametersPlaces.emplace_back(results[1].str(),
|
||||
placeIndex);
|
||||
}
|
||||
}
|
||||
++placeIndex;
|
||||
}
|
||||
paras = results.suffix();
|
||||
}
|
||||
}
|
||||
auto pathParameterPattern =
|
||||
std::regex_replace(originPath, regex, "([^/]*)");
|
||||
auto binderInfo = std::make_shared<CtrlBinder>();
|
||||
binderInfo->filterNames_ = filters;
|
||||
binderInfo->handlerName_ = handlerName;
|
||||
binderInfo->binderPtr_ = binder;
|
||||
binderInfo->parameterPlaces_ = std::move(places);
|
||||
binderInfo->queryParametersPlaces_ = std::move(parametersPlaces);
|
||||
drogon::app().getLoop()->queueInLoop([binderInfo]() {
|
||||
// Recreate this with the correct number of threads.
|
||||
binderInfo->responseCache_ = IOThreadStorage<HttpResponsePtr>();
|
||||
});
|
||||
bool routingRequiresRegex = (originPath != pathParameterPattern);
|
||||
HttpControllerRouterItem *existingRouterItemPtr = nullptr;
|
||||
|
||||
// If exists another controllers on the same route. Updathe them then exit
|
||||
if (routingRequiresRegex) {
|
||||
for (auto &router : ctrlVector_) {
|
||||
if (router.pathParameterPattern_ == pathParameterPattern)
|
||||
existingRouterItemPtr = &router;
|
||||
}
|
||||
} else {
|
||||
std::string loweredPath;
|
||||
loweredPath.resize(originPath.size());
|
||||
std::transform(originPath.begin(),
|
||||
originPath.end(),
|
||||
loweredPath.begin(),
|
||||
tolower);
|
||||
auto it = ctrlMap_.find(loweredPath);
|
||||
if (it != ctrlMap_.end())
|
||||
existingRouterItemPtr = &it->second;
|
||||
}
|
||||
|
||||
if (existingRouterItemPtr != nullptr) {
|
||||
auto &router = *existingRouterItemPtr;
|
||||
if (!validMethods.empty()) {
|
||||
for (auto const &method : validMethods) {
|
||||
router.binders_[method] = binderInfo;
|
||||
if (method == Options)
|
||||
binderInfo->isCORS_ = true;
|
||||
}
|
||||
} else {
|
||||
binderInfo->isCORS_ = true;
|
||||
for (int i = 0; i < Invalid; ++i)
|
||||
router.binders_[i] = binderInfo;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
struct HttpControllerRouterItem router;
|
||||
router.pathParameterPattern_ = pathParameterPattern;
|
||||
router.pathPattern_ = path;
|
||||
if (!validMethods.empty()) {
|
||||
for (auto const &method : validMethods) {
|
||||
router.binders_[method] = binderInfo;
|
||||
if (method == Options)
|
||||
binderInfo->isCORS_ = true;
|
||||
}
|
||||
} else {
|
||||
binderInfo->isCORS_ = true;
|
||||
for (int i = 0; i < Invalid; ++i)
|
||||
router.binders_[i] = binderInfo;
|
||||
}
|
||||
|
||||
if (routingRequiresRegex)
|
||||
ctrlVector_.push_back(std::move(router));
|
||||
else {
|
||||
std::string loweredPath;
|
||||
loweredPath.resize(originPath.size());
|
||||
std::transform(originPath.begin(),
|
||||
originPath.end(),
|
||||
loweredPath.begin(),
|
||||
tolower);
|
||||
ctrlMap_[loweredPath] = std::move(router);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpControllersRouter::route(
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
// Find http controller
|
||||
HttpControllerRouterItem *routerItemPtr = nullptr;
|
||||
std::smatch result;
|
||||
std::string loweredPath = req->path();
|
||||
std::transform(loweredPath.begin(),
|
||||
loweredPath.end(),
|
||||
loweredPath.begin(),
|
||||
tolower);
|
||||
|
||||
auto it = ctrlMap_.find(loweredPath);
|
||||
// Try to find a controller in the hash map. If can't linear search
|
||||
// with regex.
|
||||
if (it != ctrlMap_.end()) {
|
||||
routerItemPtr = &it->second;
|
||||
} else {
|
||||
for (auto &item : ctrlVector_) {
|
||||
auto const &ctrlRegex = item.regex_;
|
||||
if (std::regex_match(req->path(), result, ctrlRegex)) {
|
||||
routerItemPtr = &item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No handler found
|
||||
if (routerItemPtr == nullptr) {
|
||||
doWhenNoHandlerFound(req, std::move(callback));
|
||||
return;
|
||||
}
|
||||
|
||||
HttpControllerRouterItem &routerItem = *routerItemPtr;
|
||||
assert(Invalid > req->method());
|
||||
req->setMatchedPathPattern(routerItem.pathPattern_);
|
||||
auto &binder = routerItem.binders_[req->method()];
|
||||
if (!binder) {
|
||||
// Invalid Http Method
|
||||
if (req->method() != Options) {
|
||||
callback(app().getCustomErrorHandler()(k405MethodNotAllowed));
|
||||
} else {
|
||||
callback(app().getCustomErrorHandler()(k403Forbidden));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!postRoutingObservers_.empty()) {
|
||||
for (auto &observer : postRoutingObservers_) {
|
||||
observer(req);
|
||||
}
|
||||
}
|
||||
if (postRoutingAdvices_.empty()) {
|
||||
if (!binder->filters_.empty()) {
|
||||
auto &filters = binder->filters_;
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)> >(
|
||||
std::move(callback));
|
||||
filters_function::doFilters(filters,
|
||||
req,
|
||||
callbackPtr,
|
||||
[req,
|
||||
callbackPtr,
|
||||
this,
|
||||
&binder,
|
||||
&routerItem,
|
||||
result = std::move(result)]() mutable {
|
||||
doPreHandlingAdvices(
|
||||
binder,
|
||||
routerItem,
|
||||
req,
|
||||
std::move(result),
|
||||
std::move(*callbackPtr));
|
||||
});
|
||||
} else {
|
||||
doPreHandlingAdvices(binder,
|
||||
routerItem,
|
||||
req,
|
||||
std::move(result),
|
||||
std::move(callback));
|
||||
}
|
||||
} else {
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)> >(
|
||||
std::move(callback));
|
||||
doAdvicesChain(postRoutingAdvices_,
|
||||
0,
|
||||
req,
|
||||
callbackPtr,
|
||||
[&binder,
|
||||
callbackPtr,
|
||||
req,
|
||||
this,
|
||||
&routerItem,
|
||||
result = std::move(result)]() mutable {
|
||||
if (!binder->filters_.empty()) {
|
||||
auto &filters = binder->filters_;
|
||||
filters_function::doFilters(
|
||||
filters,
|
||||
req,
|
||||
callbackPtr,
|
||||
[this,
|
||||
req,
|
||||
callbackPtr,
|
||||
&binder,
|
||||
&routerItem,
|
||||
result = std::move(result)]() mutable {
|
||||
doPreHandlingAdvices(binder,
|
||||
routerItem,
|
||||
req,
|
||||
std::move(result),
|
||||
std::move(
|
||||
*callbackPtr));
|
||||
});
|
||||
} else {
|
||||
doPreHandlingAdvices(binder,
|
||||
routerItem,
|
||||
req,
|
||||
std::move(result),
|
||||
std::move(*callbackPtr));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void HttpControllersRouter::doControllerHandler(
|
||||
const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const HttpControllerRouterItem & /*routerItem*/,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::smatch &matchResult,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
auto &responsePtr = *(ctrlBinderPtr->responseCache_);
|
||||
if (responsePtr) {
|
||||
if (responsePtr->expiredTime() == 0 ||
|
||||
(trantor::Date::now() <
|
||||
responsePtr->creationDate().after(
|
||||
static_cast<double>(responsePtr->expiredTime())))) {
|
||||
// use cached response!
|
||||
LOG_TRACE << "Use cached response";
|
||||
invokeCallback(callback, req, responsePtr);
|
||||
return;
|
||||
} else {
|
||||
responsePtr.reset();
|
||||
}
|
||||
}
|
||||
|
||||
std::deque<std::string> params(ctrlBinderPtr->parameterPlaces_.size());
|
||||
|
||||
for (size_t j = 1; j < matchResult.size(); ++j) {
|
||||
if (!matchResult[j].matched)
|
||||
continue;
|
||||
size_t place = j;
|
||||
if (j <= ctrlBinderPtr->parameterPlaces_.size()) {
|
||||
place = ctrlBinderPtr->parameterPlaces_[j - 1];
|
||||
}
|
||||
if (place > params.size())
|
||||
params.resize(place);
|
||||
params[place - 1] = matchResult[j].str();
|
||||
LOG_TRACE << "place=" << place << " para:" << params[place - 1];
|
||||
}
|
||||
|
||||
if (!ctrlBinderPtr->queryParametersPlaces_.empty()) {
|
||||
auto &queryPara = req->getParameters();
|
||||
for (auto const ¶Place : ctrlBinderPtr->queryParametersPlaces_) {
|
||||
auto place = paraPlace.second;
|
||||
if (place > params.size())
|
||||
params.resize(place);
|
||||
auto iter = queryPara.find(paraPlace.first);
|
||||
if (iter != queryPara.end()) {
|
||||
params[place - 1] = iter->second;
|
||||
} else {
|
||||
params[place - 1] = std::string{};
|
||||
}
|
||||
}
|
||||
}
|
||||
ctrlBinderPtr->binderPtr_->handleHttpRequest(
|
||||
params,
|
||||
req,
|
||||
[this, req, ctrlBinderPtr, callback = std::move(callback)](
|
||||
const HttpResponsePtr &resp) {
|
||||
if (resp->expiredTime() >= 0 && resp->statusCode() != k404NotFound) {
|
||||
// cache the response;
|
||||
static_cast<HttpResponseImpl *>(resp.get())->makeHeaderString();
|
||||
auto loop = req->getLoop();
|
||||
if (loop->isInLoopThread()) {
|
||||
ctrlBinderPtr->responseCache_.setThreadData(resp);
|
||||
} else {
|
||||
req->getLoop()->queueInLoop([resp, &ctrlBinderPtr]() {
|
||||
ctrlBinderPtr->responseCache_.setThreadData(resp);
|
||||
});
|
||||
}
|
||||
}
|
||||
invokeCallback(callback, req, resp);
|
||||
});
|
||||
}
|
||||
|
||||
void HttpControllersRouter::doPreHandlingAdvices(
|
||||
const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const HttpControllerRouterItem &routerItem,
|
||||
const HttpRequestImplPtr &req,
|
||||
std::smatch &&matchResult,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
if (req->method() == Options) {
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setContentTypeCode(ContentType::CT_TEXT_PLAIN);
|
||||
std::string methods = "OPTIONS,";
|
||||
if (routerItem.binders_[Get] && routerItem.binders_[Get]->isCORS_) {
|
||||
methods.append("GET,HEAD,");
|
||||
}
|
||||
if (routerItem.binders_[Post] && routerItem.binders_[Post]->isCORS_) {
|
||||
methods.append("POST,");
|
||||
}
|
||||
if (routerItem.binders_[Put] && routerItem.binders_[Put]->isCORS_) {
|
||||
methods.append("PUT,");
|
||||
}
|
||||
if (routerItem.binders_[Delete] && routerItem.binders_[Delete]->isCORS_) {
|
||||
methods.append("DELETE,");
|
||||
}
|
||||
if (routerItem.binders_[Patch] && routerItem.binders_[Patch]->isCORS_) {
|
||||
methods.append("PATCH,");
|
||||
}
|
||||
methods.resize(methods.length() - 1);
|
||||
resp->addHeader("ALLOW", methods);
|
||||
auto &origin = req->getHeader("Origin");
|
||||
if (origin.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Origin", "*");
|
||||
} else {
|
||||
resp->addHeader("Access-Control-Allow-Origin", origin);
|
||||
}
|
||||
resp->addHeader("Access-Control-Allow-Methods", methods);
|
||||
auto &headers = req->getHeaderBy("access-control-request-headers");
|
||||
if (!headers.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Headers", headers);
|
||||
}
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
if (!preHandlingObservers_.empty()) {
|
||||
for (auto &observer : preHandlingObservers_) {
|
||||
observer(req);
|
||||
}
|
||||
}
|
||||
if (preHandlingAdvices_.empty()) {
|
||||
doControllerHandler(
|
||||
ctrlBinderPtr, routerItem, req, matchResult, std::move(callback));
|
||||
} else {
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)> >(
|
||||
std::move(callback));
|
||||
doAdvicesChain(
|
||||
preHandlingAdvices_,
|
||||
0,
|
||||
req,
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)> >(
|
||||
[req, callbackPtr](const HttpResponsePtr &resp) {
|
||||
HttpAppFrameworkImpl::instance().callCallback(req,
|
||||
resp,
|
||||
*callbackPtr);
|
||||
}),
|
||||
[this,
|
||||
ctrlBinderPtr,
|
||||
&routerItem,
|
||||
req,
|
||||
callbackPtr,
|
||||
result = std::move(matchResult)]() {
|
||||
doControllerHandler(ctrlBinderPtr,
|
||||
routerItem,
|
||||
req,
|
||||
result,
|
||||
std::move(*callbackPtr));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void HttpControllersRouter::invokeCallback(
|
||||
const std::function<void(const HttpResponsePtr &)> &callback,
|
||||
const HttpRequestImplPtr &req,
|
||||
const HttpResponsePtr &resp) {
|
||||
for (auto &advice : postHandlingAdvices_) {
|
||||
advice(req, resp);
|
||||
}
|
||||
HttpAppFrameworkImpl::instance().callCallback(req, resp, callback);
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* HttpControllersRouter.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 "impl_forwards.h"
|
||||
#include <drogon/HttpBinder.h>
|
||||
#include <drogon/IOThreadStorage.h>
|
||||
#include <drogon/drogon_callbacks.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace drogon {
|
||||
class HttpControllersRouter : public trantor::NonCopyable {
|
||||
public:
|
||||
HttpControllersRouter(
|
||||
StaticFileRouter &router,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
AdviceCallback &&,
|
||||
AdviceChainCallback &&)> >
|
||||
&postRoutingAdvices,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &)> >
|
||||
&postRoutingObservers,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
AdviceCallback &&,
|
||||
AdviceChainCallback &&)> >
|
||||
&preHandlingAdvices,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &)> >
|
||||
&preHandlingObservers,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
const HttpResponsePtr &)> >
|
||||
&postHandlingAdvices) :
|
||||
fileRouter_(router),
|
||||
postRoutingAdvices_(postRoutingAdvices),
|
||||
preHandlingAdvices_(preHandlingAdvices),
|
||||
postRoutingObservers_(postRoutingObservers),
|
||||
preHandlingObservers_(preHandlingObservers),
|
||||
postHandlingAdvices_(postHandlingAdvices) {
|
||||
}
|
||||
void init(const std::vector<trantor::EventLoop *> &ioLoops);
|
||||
void addHttpPath(const std::string &path,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
const std::vector<HttpMethod> &validMethods,
|
||||
const std::vector<std::string> &filters,
|
||||
const std::string &handlerName = "");
|
||||
void addHttpRegex(const std::string ®Exp,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
const std::vector<HttpMethod> &validMethods,
|
||||
const std::vector<std::string> &filters,
|
||||
const std::string &handlerName = "");
|
||||
void route(const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
std::vector<std::tuple<std::string, HttpMethod, std::string> >
|
||||
getHandlersInfo() const;
|
||||
|
||||
private:
|
||||
StaticFileRouter &fileRouter_;
|
||||
struct CtrlBinder {
|
||||
internal::HttpBinderBasePtr binderPtr_;
|
||||
std::string handlerName_;
|
||||
std::vector<std::string> filterNames_;
|
||||
std::vector<std::shared_ptr<HttpFilterBase> > filters_;
|
||||
std::vector<size_t> parameterPlaces_;
|
||||
std::vector<std::pair<std::string, size_t> > queryParametersPlaces_;
|
||||
IOThreadStorage<HttpResponsePtr> responseCache_;
|
||||
bool isCORS_{ false };
|
||||
};
|
||||
using CtrlBinderPtr = std::shared_ptr<CtrlBinder>;
|
||||
struct HttpControllerRouterItem {
|
||||
std::string pathParameterPattern_;
|
||||
std::string pathPattern_;
|
||||
std::regex regex_;
|
||||
CtrlBinderPtr binders_[Invalid]{
|
||||
nullptr
|
||||
}; // The enum value of Invalid is the http methods number
|
||||
};
|
||||
std::unordered_map<std::string, HttpControllerRouterItem> ctrlMap_;
|
||||
std::vector<HttpControllerRouterItem> ctrlVector_;
|
||||
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
AdviceCallback &&,
|
||||
AdviceChainCallback &&)> >
|
||||
&postRoutingAdvices_;
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
AdviceCallback &&,
|
||||
AdviceChainCallback &&)> >
|
||||
&preHandlingAdvices_;
|
||||
const std::vector<std::function<void(const HttpRequestPtr &)> >
|
||||
&postRoutingObservers_;
|
||||
const std::vector<std::function<void(const HttpRequestPtr &)> >
|
||||
&preHandlingObservers_;
|
||||
const std::vector<
|
||||
std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)> >
|
||||
&postHandlingAdvices_;
|
||||
|
||||
void doPreHandlingAdvices(
|
||||
const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const HttpControllerRouterItem &routerItem,
|
||||
const HttpRequestImplPtr &req,
|
||||
std::smatch &&matchResult,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
|
||||
void doControllerHandler(
|
||||
const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const HttpControllerRouterItem &routerItem,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::smatch &matchResult,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
void invokeCallback(
|
||||
const std::function<void(const HttpResponsePtr &)> &callback,
|
||||
const HttpRequestImplPtr &req,
|
||||
const HttpResponsePtr &resp);
|
||||
void doWhenNoHandlerFound(
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
};
|
||||
} // namespace drogon
|
@ -43,12 +43,13 @@ static inline void doResponseCreateAdvices(
|
||||
}
|
||||
static inline HttpResponsePtr genHttpResponse(const std::string &viewName,
|
||||
const HttpViewData &data) {
|
||||
/*
|
||||
auto templ = DrTemplateBase::newTemplate(viewName);
|
||||
if (templ) {
|
||||
auto res = HttpResponse::newHttpResponse();
|
||||
res->setBody(templ->genText(data));
|
||||
return res;
|
||||
}
|
||||
}*/
|
||||
return drogon::HttpResponse::newNotFoundResponse();
|
||||
}
|
||||
} // namespace drogon
|
||||
|
@ -1,343 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @file HttpSimpleControllersRouter.cc
|
||||
* @author 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 "HttpSimpleControllersRouter.h"
|
||||
#include "AOPAdvice.h"
|
||||
#include "FiltersFunction.h"
|
||||
#include "HttpAppFrameworkImpl.h"
|
||||
#include "HttpControllersRouter.h"
|
||||
#include "HttpRequestImpl.h"
|
||||
#include "HttpResponseImpl.h"
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
#include <drogon/utils/HttpConstraint.h>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
void HttpSimpleControllersRouter::registerHttpSimpleController(
|
||||
const std::string &pathName,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &filtersAndMethods) {
|
||||
assert(!pathName.empty());
|
||||
assert(!ctrlName.empty());
|
||||
std::string path(pathName);
|
||||
std::transform(pathName.begin(), pathName.end(), path.begin(), tolower);
|
||||
std::lock_guard<std::mutex> guard(simpleCtrlMutex_);
|
||||
std::vector<HttpMethod> validMethods;
|
||||
std::vector<std::string> filters;
|
||||
for (auto const &filterOrMethod : filtersAndMethods) {
|
||||
if (filterOrMethod.type() == internal::ConstraintType::HttpFilter) {
|
||||
filters.push_back(filterOrMethod.getFilterName());
|
||||
} else if (filterOrMethod.type() == internal::ConstraintType::HttpMethod) {
|
||||
validMethods.push_back(filterOrMethod.getHttpMethod());
|
||||
} else {
|
||||
LOG_ERROR << "Invalid controller constraint type";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
auto &item = simpleCtrlMap_[path];
|
||||
auto binder = std::make_shared<CtrlBinder>();
|
||||
binder->controllerName_ = ctrlName;
|
||||
binder->filterNames_ = filters;
|
||||
drogon::app().getLoop()->queueInLoop([binder, ctrlName]() {
|
||||
auto &object_ = DrClassMap::getSingleInstance(ctrlName);
|
||||
auto controller =
|
||||
std::dynamic_pointer_cast<HttpSimpleControllerBase>(object_);
|
||||
binder->controller_ = controller;
|
||||
// Recreate this with the correct number of threads.
|
||||
binder->responseCache_ = IOThreadStorage<HttpResponsePtr>();
|
||||
});
|
||||
|
||||
if (validMethods.size() > 0) {
|
||||
for (auto const &method : validMethods) {
|
||||
item.binders_[method] = binder;
|
||||
if (method == Options) {
|
||||
binder->isCORS_ = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// All HTTP methods are valid
|
||||
for (size_t i = 0; i < Invalid; ++i) {
|
||||
item.binders_[i] = binder;
|
||||
}
|
||||
binder->isCORS_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void HttpSimpleControllersRouter::route(
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
std::string pathLower(req->path().length(), 0);
|
||||
std::transform(req->path().begin(),
|
||||
req->path().end(),
|
||||
pathLower.begin(),
|
||||
tolower);
|
||||
auto iter = simpleCtrlMap_.find(pathLower);
|
||||
if (iter != simpleCtrlMap_.end()) {
|
||||
auto &ctrlInfo = iter->second;
|
||||
req->setMatchedPathPattern(iter->first);
|
||||
auto &binder = ctrlInfo.binders_[req->method()];
|
||||
if (!binder) {
|
||||
// Invalid Http Method
|
||||
if (req->method() != Options) {
|
||||
callback(app().getCustomErrorHandler()(k405MethodNotAllowed));
|
||||
} else {
|
||||
callback(app().getCustomErrorHandler()(k403Forbidden));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Do post routing advices.
|
||||
if (!postRoutingObservers_.empty()) {
|
||||
for (auto &observer : postRoutingObservers_) {
|
||||
observer(req);
|
||||
}
|
||||
}
|
||||
auto &filters = ctrlInfo.binders_[req->method()]->filters_;
|
||||
if (postRoutingAdvices_.empty()) {
|
||||
if (!filters.empty()) {
|
||||
auto callbackPtr = std::make_shared<
|
||||
std::function<void(const HttpResponsePtr &)> >(
|
||||
std::move(callback));
|
||||
filters_function::doFilters(
|
||||
filters,
|
||||
req,
|
||||
callbackPtr,
|
||||
[this, &ctrlInfo, req, callbackPtr, &binder]() mutable {
|
||||
doPreHandlingAdvices(binder,
|
||||
ctrlInfo,
|
||||
req,
|
||||
std::move(*callbackPtr));
|
||||
});
|
||||
} else {
|
||||
doPreHandlingAdvices(binder,
|
||||
ctrlInfo,
|
||||
req,
|
||||
std::move(callback));
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)> >(
|
||||
std::move(callback));
|
||||
doAdvicesChain(
|
||||
postRoutingAdvices_,
|
||||
0,
|
||||
req,
|
||||
callbackPtr,
|
||||
[callbackPtr,
|
||||
&filters,
|
||||
req,
|
||||
&ctrlInfo,
|
||||
this,
|
||||
&binder]() mutable {
|
||||
if (!filters.empty()) {
|
||||
filters_function::doFilters(
|
||||
filters,
|
||||
req,
|
||||
callbackPtr,
|
||||
[this,
|
||||
&ctrlInfo,
|
||||
req,
|
||||
callbackPtr,
|
||||
&binder]() mutable {
|
||||
doPreHandlingAdvices(binder,
|
||||
ctrlInfo,
|
||||
req,
|
||||
std::move(*callbackPtr));
|
||||
});
|
||||
} else {
|
||||
doPreHandlingAdvices(binder,
|
||||
ctrlInfo,
|
||||
req,
|
||||
std::move(*callbackPtr));
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
httpCtrlsRouter_.route(req, std::move(callback));
|
||||
}
|
||||
|
||||
void HttpSimpleControllersRouter::doControllerHandler(
|
||||
const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
auto &controller = ctrlBinderPtr->controller_;
|
||||
if (controller) {
|
||||
auto &responsePtr = *(ctrlBinderPtr->responseCache_);
|
||||
if (responsePtr) {
|
||||
if (responsePtr->expiredTime() == 0 ||
|
||||
(trantor::Date::now() <
|
||||
responsePtr->creationDate().after(
|
||||
static_cast<double>(responsePtr->expiredTime())))) {
|
||||
// use cached response!
|
||||
LOG_TRACE << "Use cached response";
|
||||
invokeCallback(callback, req, responsePtr);
|
||||
return;
|
||||
} else {
|
||||
responsePtr.reset();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
controller->asyncHandleHttpRequest(
|
||||
req,
|
||||
[this, req, callback, &ctrlBinderPtr](
|
||||
const HttpResponsePtr &resp) {
|
||||
auto newResp = resp;
|
||||
if (resp->expiredTime() >= 0 &&
|
||||
resp->statusCode() != k404NotFound) {
|
||||
// cache the response;
|
||||
static_cast<HttpResponseImpl *>(resp.get())
|
||||
->makeHeaderString();
|
||||
auto loop = req->getLoop();
|
||||
|
||||
if (loop->isInLoopThread()) {
|
||||
ctrlBinderPtr->responseCache_.setThreadData(resp);
|
||||
} else {
|
||||
loop->queueInLoop([resp, &ctrlBinderPtr]() {
|
||||
ctrlBinderPtr->responseCache_.setThreadData(
|
||||
resp);
|
||||
});
|
||||
}
|
||||
}
|
||||
invokeCallback(callback, req, newResp);
|
||||
});
|
||||
} catch (const std::exception &e) {
|
||||
app().getExceptionHandler()(e, req, std::move(callback));
|
||||
return;
|
||||
} catch (...) {
|
||||
LOG_ERROR << "Exception not derived from std::exception";
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
const std::string &ctrlName = ctrlBinderPtr->controllerName_;
|
||||
LOG_ERROR << "can't find controller " << ctrlName;
|
||||
auto res = drogon::HttpResponse::newNotFoundResponse();
|
||||
invokeCallback(callback, req, res);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::tuple<std::string, HttpMethod, std::string> >
|
||||
HttpSimpleControllersRouter::getHandlersInfo() const {
|
||||
std::vector<std::tuple<std::string, HttpMethod, std::string> > ret;
|
||||
for (auto &item : simpleCtrlMap_) {
|
||||
for (size_t i = 0; i < Invalid; ++i) {
|
||||
if (item.second.binders_[i]) {
|
||||
auto info = std::tuple<std::string, HttpMethod, std::string>(
|
||||
item.first,
|
||||
(HttpMethod)i,
|
||||
std::string("HttpSimpleController: ") +
|
||||
item.second.binders_[i]->controllerName_);
|
||||
ret.emplace_back(std::move(info));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HttpSimpleControllersRouter::init(
|
||||
const std::vector<trantor::EventLoop *> & /*ioLoops*/) {
|
||||
for (auto &iter : simpleCtrlMap_) {
|
||||
auto &item = iter.second;
|
||||
for (size_t i = 0; i < Invalid; ++i) {
|
||||
auto &binder = item.binders_[i];
|
||||
if (binder) {
|
||||
binder->filters_ =
|
||||
filters_function::createFilters(binder->filterNames_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpSimpleControllersRouter::doPreHandlingAdvices(
|
||||
const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const SimpleControllerRouterItem &routerItem,
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
if (req->method() == Options) {
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setContentTypeCode(ContentType::CT_TEXT_PLAIN);
|
||||
std::string methods = "OPTIONS,";
|
||||
if (routerItem.binders_[Get] && routerItem.binders_[Get]->isCORS_) {
|
||||
methods.append("GET,HEAD,");
|
||||
}
|
||||
if (routerItem.binders_[Post] && routerItem.binders_[Post]->isCORS_) {
|
||||
methods.append("POST,");
|
||||
}
|
||||
if (routerItem.binders_[Put] && routerItem.binders_[Put]->isCORS_) {
|
||||
methods.append("PUT,");
|
||||
}
|
||||
if (routerItem.binders_[Delete] && routerItem.binders_[Delete]->isCORS_) {
|
||||
methods.append("DELETE,");
|
||||
}
|
||||
if (routerItem.binders_[Patch] && routerItem.binders_[Patch]->isCORS_) {
|
||||
methods.append("PATCH,");
|
||||
}
|
||||
methods.resize(methods.length() - 1);
|
||||
resp->addHeader("ALLOW", methods);
|
||||
|
||||
auto &origin = req->getHeader("Origin");
|
||||
if (origin.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Origin", "*");
|
||||
} else {
|
||||
resp->addHeader("Access-Control-Allow-Origin", origin);
|
||||
}
|
||||
resp->addHeader("Access-Control-Allow-Methods", methods);
|
||||
auto &headers = req->getHeaderBy("access-control-request-headers");
|
||||
if (!headers.empty()) {
|
||||
resp->addHeader("Access-Control-Allow-Headers", headers);
|
||||
}
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
if (!preHandlingObservers_.empty()) {
|
||||
for (auto &observer : preHandlingObservers_) {
|
||||
observer(req);
|
||||
}
|
||||
}
|
||||
if (preHandlingAdvices_.empty()) {
|
||||
doControllerHandler(ctrlBinderPtr, req, std::move(callback));
|
||||
} else {
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)> >(
|
||||
std::move(callback));
|
||||
doAdvicesChain(
|
||||
preHandlingAdvices_,
|
||||
0,
|
||||
req,
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)> >(
|
||||
[req, callbackPtr](const HttpResponsePtr &resp) {
|
||||
HttpAppFrameworkImpl::instance().callCallback(req,
|
||||
resp,
|
||||
*callbackPtr);
|
||||
}),
|
||||
[this, ctrlBinderPtr, req, callbackPtr]() {
|
||||
doControllerHandler(ctrlBinderPtr,
|
||||
req,
|
||||
std::move(*callbackPtr));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void HttpSimpleControllersRouter::invokeCallback(
|
||||
const std::function<void(const HttpResponsePtr &)> &callback,
|
||||
const HttpRequestImplPtr &req,
|
||||
const HttpResponsePtr &resp) {
|
||||
for (auto &advice : postHandlingAdvices_) {
|
||||
advice(req, resp);
|
||||
}
|
||||
HttpAppFrameworkImpl::instance().callCallback(req, resp, callback);
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* HttpSimpleControllersRouter.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 "impl_forwards.h"
|
||||
#include <drogon/IOThreadStorage.h>
|
||||
#include <drogon/drogon_callbacks.h>
|
||||
#include <drogon/utils/HttpConstraint.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <regex>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace drogon {
|
||||
class HttpSimpleControllersRouter : public trantor::NonCopyable {
|
||||
public:
|
||||
HttpSimpleControllersRouter(
|
||||
HttpControllersRouter &httpCtrlRouter,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
AdviceCallback &&,
|
||||
AdviceChainCallback &&)> >
|
||||
&postRoutingAdvices,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &)> >
|
||||
&postRoutingObservers,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
AdviceCallback &&,
|
||||
AdviceChainCallback &&)> >
|
||||
&preHandlingAdvices,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &)> >
|
||||
&preHandlingObservers,
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
const HttpResponsePtr &)> >
|
||||
&postHandlingAdvices) :
|
||||
httpCtrlsRouter_(httpCtrlRouter),
|
||||
postRoutingAdvices_(postRoutingAdvices),
|
||||
preHandlingAdvices_(preHandlingAdvices),
|
||||
postRoutingObservers_(postRoutingObservers),
|
||||
preHandlingObservers_(preHandlingObservers),
|
||||
postHandlingAdvices_(postHandlingAdvices) {
|
||||
}
|
||||
|
||||
void registerHttpSimpleController(
|
||||
const std::string &pathName,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &filtersAndMethods);
|
||||
void route(const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
void init(const std::vector<trantor::EventLoop *> &ioLoops);
|
||||
|
||||
std::vector<std::tuple<std::string, HttpMethod, std::string> >
|
||||
getHandlersInfo() const;
|
||||
|
||||
private:
|
||||
HttpControllersRouter &httpCtrlsRouter_;
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
AdviceCallback &&,
|
||||
AdviceChainCallback &&)> >
|
||||
&postRoutingAdvices_;
|
||||
const std::vector<std::function<void(const HttpRequestPtr &,
|
||||
AdviceCallback &&,
|
||||
AdviceChainCallback &&)> >
|
||||
&preHandlingAdvices_;
|
||||
const std::vector<std::function<void(const HttpRequestPtr &)> >
|
||||
&postRoutingObservers_;
|
||||
const std::vector<std::function<void(const HttpRequestPtr &)> >
|
||||
&preHandlingObservers_;
|
||||
|
||||
const std::vector<
|
||||
std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)> >
|
||||
&postHandlingAdvices_;
|
||||
struct CtrlBinder {
|
||||
std::shared_ptr<HttpSimpleControllerBase> controller_;
|
||||
std::string controllerName_;
|
||||
std::vector<std::string> filterNames_;
|
||||
std::vector<std::shared_ptr<HttpFilterBase> > filters_;
|
||||
IOThreadStorage<HttpResponsePtr> responseCache_;
|
||||
bool isCORS_{ false };
|
||||
};
|
||||
|
||||
using CtrlBinderPtr = std::shared_ptr<CtrlBinder>;
|
||||
|
||||
struct SimpleControllerRouterItem {
|
||||
CtrlBinderPtr binders_[Invalid];
|
||||
};
|
||||
std::unordered_map<std::string, SimpleControllerRouterItem> simpleCtrlMap_;
|
||||
std::mutex simpleCtrlMutex_;
|
||||
|
||||
void doPreHandlingAdvices(
|
||||
const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const SimpleControllerRouterItem &routerItem,
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
void doControllerHandler(
|
||||
const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
void invokeCallback(
|
||||
const std::function<void(const HttpResponsePtr &)> &callback,
|
||||
const HttpRequestImplPtr &req,
|
||||
const HttpResponsePtr &resp);
|
||||
};
|
||||
} // namespace drogon
|
@ -1,50 +0,0 @@
|
||||
// this file is generated by program automatically,don't modify it!
|
||||
|
||||
/**
|
||||
*
|
||||
* NotFound.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 <drogon/NotFound.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
std::string NotFound::genText(const HttpViewData &NotFound_view_data) {
|
||||
std::stringstream NotFound_tmp_stream;
|
||||
NotFound_tmp_stream << "<html>\n";
|
||||
NotFound_tmp_stream << "<head><title>404 Not Found</title></head>\n";
|
||||
NotFound_tmp_stream << "<body bgcolor=\"white\">\n";
|
||||
NotFound_tmp_stream << "<center><h1>404 Not Found</h1></center>\n";
|
||||
NotFound_tmp_stream << "<hr><center>drogon/";
|
||||
NotFound_tmp_stream << NotFound_view_data.get<std::string>("version");
|
||||
NotFound_tmp_stream << "</center>\n";
|
||||
NotFound_tmp_stream << "</body>\n";
|
||||
NotFound_tmp_stream << "</html>\n";
|
||||
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly "
|
||||
"error page -->\n";
|
||||
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly "
|
||||
"error page -->\n";
|
||||
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly "
|
||||
"error page -->\n";
|
||||
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly "
|
||||
"error page -->\n";
|
||||
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly "
|
||||
"error page -->\n";
|
||||
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly "
|
||||
"error page -->\n";
|
||||
return NotFound_tmp_stream.str();
|
||||
}
|
@ -56,10 +56,12 @@ void PluginsManager::initializeAllPlugins(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pluginPtr->setInitializedCallback([this](PluginBase *p) {
|
||||
LOG_TRACE << "Plugin " << p->className() << " initialized!";
|
||||
//LOG_TRACE << "Plugin " << p->className() << " initialized!";
|
||||
initializedPlugins_.push_back(p);
|
||||
});
|
||||
|
||||
plugins.push_back(pluginPtr);
|
||||
}
|
||||
// Initialize them, Depth first
|
||||
@ -70,6 +72,8 @@ void PluginsManager::initializeAllPlugins(
|
||||
}
|
||||
|
||||
PluginBase *PluginsManager::getPlugin(const std::string &pluginName) {
|
||||
/*
|
||||
|
||||
auto iter = pluginsMap_.find(pluginName);
|
||||
if (iter == pluginsMap_.end()) {
|
||||
auto *p = DrClassMap::newObject(pluginName);
|
||||
@ -85,5 +89,8 @@ PluginBase *PluginsManager::getPlugin(const std::string &pluginName) {
|
||||
} else {
|
||||
return iter->second.get();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return nullptr;
|
||||
}
|
@ -136,7 +136,7 @@ void StaticFileRouter::route(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (location.filters_.empty()) {
|
||||
sendStaticFileResponse(filePath,
|
||||
req,
|
||||
@ -144,9 +144,11 @@ void StaticFileRouter::route(
|
||||
string_view{
|
||||
location.defaultContentType_ });
|
||||
} else {
|
||||
|
||||
auto callbackPtr = std::make_shared<
|
||||
std::function<void(const drogon::HttpResponsePtr &)> >(
|
||||
std::move(callback));
|
||||
|
||||
filters_function::doFilters(
|
||||
location.filters_,
|
||||
req,
|
||||
@ -161,7 +163,7 @@ void StaticFileRouter::route(
|
||||
std::move(*callbackPtr),
|
||||
string_view{ contentType });
|
||||
});
|
||||
}
|
||||
}*/
|
||||
|
||||
return;
|
||||
}
|
||||
@ -205,6 +207,7 @@ void StaticFileRouter::sendStaticFileResponse(
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
const string_view &defaultContentType) { // find cached response
|
||||
|
||||
HttpResponsePtr cachedResp;
|
||||
auto &cacheMap = staticFilesCache_->getThreadData();
|
||||
auto iter = cacheMap.find(filePath);
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FiltersFunction.h"
|
||||
#include "impl_forwards.h"
|
||||
#include <drogon/CacheMap.h>
|
||||
#include <drogon/IOThreadStorage.h>
|
||||
@ -123,7 +122,9 @@ private:
|
||||
std::vector<std::pair<std::string, std::string> > headers_;
|
||||
bool implicitPageEnable_{ true };
|
||||
std::string implicitPage_{ "index.html" };
|
||||
|
||||
DefaultHandler defaultHandler_ = StaticFileRouter::defaultHandler;
|
||||
|
||||
struct Location {
|
||||
std::string uriPrefix_;
|
||||
std::string defaultContentType_;
|
||||
@ -132,7 +133,8 @@ private:
|
||||
bool isCaseSensitive_;
|
||||
bool allowAll_;
|
||||
bool isRecursive_;
|
||||
std::vector<std::shared_ptr<drogon::HttpFilterBase> > filters_;
|
||||
//std::vector<std::shared_ptr<drogon::HttpFilterBase> > filters_;
|
||||
|
||||
Location(const std::string &uriPrefix,
|
||||
const std::string &defaultContentType,
|
||||
const std::string &alias,
|
||||
@ -144,13 +146,14 @@ private:
|
||||
alias_(alias),
|
||||
isCaseSensitive_(isCaseSensitive),
|
||||
allowAll_(allowAll),
|
||||
isRecursive_(isRecursive),
|
||||
filters_(filters_function::createFilters(filters)) {
|
||||
if (!defaultContentType.empty()) {
|
||||
defaultContentType_ =
|
||||
std::string{ "content-type: " } + defaultContentType + "\r\n";
|
||||
}
|
||||
}
|
||||
isRecursive_(isRecursive)
|
||||
/*filters_(filters_function::createFilters(filters))*/ {
|
||||
if (!defaultContentType.empty()) {
|
||||
defaultContentType_ =
|
||||
std::string{ "content-type: " } + defaultContentType + "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
std::unique_ptr<IOThreadStorage<std::vector<Location> > > ioLocationsPtr_;
|
||||
std::vector<Location> locations_;
|
||||
|
@ -14,12 +14,10 @@
|
||||
|
||||
#include "WebsocketControllersRouter.h"
|
||||
#include "AOPAdvice.h"
|
||||
#include "FiltersFunction.h"
|
||||
#include "HttpRequestImpl.h"
|
||||
#include "HttpResponseImpl.h"
|
||||
#include "WebSocketConnectionImpl.h"
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include <drogon/WebSocketController.h>
|
||||
#include <drogon/config.h>
|
||||
#ifdef OpenSSL_FOUND
|
||||
#include <openssl/sha.h>
|
||||
@ -52,12 +50,15 @@ void WebsocketControllersRouter::registerWebSocketController(
|
||||
auto binder = std::make_shared<CtrlBinder>();
|
||||
binder->controllerName_ = ctrlName;
|
||||
binder->filterNames_ = filters;
|
||||
|
||||
/*
|
||||
drogon::app().getLoop()->queueInLoop([binder, ctrlName]() {
|
||||
auto &object_ = DrClassMap::getSingleInstance(ctrlName);
|
||||
auto controller =
|
||||
std::dynamic_pointer_cast<WebSocketControllerBase>(object_);
|
||||
binder->controller_ = controller;
|
||||
});
|
||||
});*/
|
||||
|
||||
|
||||
if (validMethods.size() > 0) {
|
||||
for (auto const &method : validMethods) {
|
||||
@ -90,6 +91,8 @@ void WebsocketControllersRouter::route(
|
||||
if (iter != wsCtrlMap_.end()) {
|
||||
auto &ctrlInfo = iter->second;
|
||||
req->setMatchedPathPattern(iter->first);
|
||||
|
||||
/*
|
||||
auto &binder = ctrlInfo.binders_[req->method()];
|
||||
if (!binder) {
|
||||
// Invalid Http Method
|
||||
@ -101,12 +104,17 @@ void WebsocketControllersRouter::route(
|
||||
}
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// Do post routing advices.
|
||||
if (!postRoutingObservers_.empty()) {
|
||||
for (auto &observer : postRoutingObservers_) {
|
||||
observer(req);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
auto &filters = ctrlInfo.binders_[req->method()]->filters_;
|
||||
if (postRoutingAdvices_.empty()) {
|
||||
if (!filters.empty()) {
|
||||
@ -176,6 +184,8 @@ void WebsocketControllersRouter::route(
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -187,6 +197,7 @@ void WebsocketControllersRouter::route(
|
||||
std::vector<std::tuple<std::string, HttpMethod, std::string> >
|
||||
WebsocketControllersRouter::getHandlersInfo() const {
|
||||
std::vector<std::tuple<std::string, HttpMethod, std::string> > ret;
|
||||
/*
|
||||
for (auto &item : wsCtrlMap_) {
|
||||
for (size_t i = 0; i < Invalid; ++i) {
|
||||
if (item.second.binders_[i]) {
|
||||
@ -198,7 +209,7 @@ WebsocketControllersRouter::getHandlersInfo() const {
|
||||
ret.emplace_back(std::move(info));
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -257,29 +268,34 @@ void WebsocketControllersRouter::doControllerHandler(
|
||||
resp->addHeader("Sec-WebSocket-Accept", base64Key);
|
||||
callback(resp);
|
||||
auto ctrlPtr = routerItem.binders_[req->method()]->controller_;
|
||||
|
||||
/*
|
||||
wsConnPtr->setMessageCallback(
|
||||
[ctrlPtr](std::string &&message,
|
||||
const WebSocketConnectionImplPtr &connPtr,
|
||||
const WebSocketMessageType &type) {
|
||||
ctrlPtr->handleNewMessage(connPtr, std::move(message), type);
|
||||
});
|
||||
|
||||
wsConnPtr->setCloseCallback(
|
||||
[ctrlPtr](const WebSocketConnectionImplPtr &connPtr) {
|
||||
ctrlPtr->handleConnectionClosed(connPtr);
|
||||
});
|
||||
ctrlPtr->handleNewConnection(req, wsConnPtr);
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
void WebsocketControllersRouter::init() {
|
||||
/*
|
||||
for (auto &iter : wsCtrlMap_) {
|
||||
auto &item = iter.second;
|
||||
for (size_t i = 0; i < Invalid; ++i) {
|
||||
auto &binder = item.binders_[i];
|
||||
if (binder) {
|
||||
binder->filters_ =
|
||||
filters_function::createFilters(binder->filterNames_);
|
||||
binder->filters_ = filters_function::createFilters(binder->filterNames_);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
@ -26,9 +26,7 @@ class WebSocketConnectionImpl;
|
||||
using WebSocketConnectionImplPtr = std::shared_ptr<WebSocketConnectionImpl>;
|
||||
class HttpRequestParser;
|
||||
class StaticFileRouter;
|
||||
class HttpControllersRouter;
|
||||
class WebsocketControllersRouter;
|
||||
class HttpSimpleControllersRouter;
|
||||
class PluginsManager;
|
||||
class ListenerManager;
|
||||
class SharedLibManager;
|
||||
|
Loading…
Reference in New Issue
Block a user