Add regex support for websocket controller (#1779)
This commit is contained in:
parent
f37a1d036f
commit
9a96a20c6e
|
@ -14,6 +14,7 @@ class WebSocketChat : public drogon::WebSocketController<WebSocketChat>
|
|||
const WebSocketConnectionPtr &) override;
|
||||
WS_PATH_LIST_BEGIN
|
||||
WS_PATH_ADD("/chat", Get);
|
||||
WS_ADD_PATH_VIA_REGEX("/[^/]*", Get);
|
||||
WS_PATH_LIST_END
|
||||
private:
|
||||
PubSubService<std::string> chatRooms_;
|
||||
|
|
|
@ -618,6 +618,18 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &constraints = {}) = 0;
|
||||
|
||||
/// Register a WebSocketController into the framework.
|
||||
/**
|
||||
* The parameters of this method are the same as those in the
|
||||
* registerHttpSimpleController() method but using regular
|
||||
* expression string for path.
|
||||
*/
|
||||
virtual HttpAppFramework ®isterWebSocketControllerRegex(
|
||||
const std::string ®Exp,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &constraints =
|
||||
std::vector<internal::HttpConstraint>{}) = 0;
|
||||
|
||||
/// Register controller objects created and initialized by the user
|
||||
/**
|
||||
* @details Drogon can only automatically create controllers using the
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
static void initPathRouting() \
|
||||
{
|
||||
#define WS_PATH_ADD(path, ...) registerSelf__(path, {__VA_ARGS__})
|
||||
#define WS_ADD_PATH_VIA_REGEX(regExp, ...) \
|
||||
registerSelfRegex__(regExp, {__VA_ARGS__})
|
||||
#define WS_PATH_LIST_END }
|
||||
|
||||
namespace drogon
|
||||
|
@ -94,6 +96,19 @@ class WebSocketController : public DrObject<T>, public WebSocketControllerBase
|
|||
constraints);
|
||||
}
|
||||
|
||||
static void registerSelfRegex__(
|
||||
const std::string ®Exp,
|
||||
const std::vector<internal::HttpConstraint> &constraints)
|
||||
{
|
||||
LOG_TRACE << "register websocket controller("
|
||||
<< WebSocketController<T, AutoCreation>::classTypeName()
|
||||
<< ") on regExp:" << regExp;
|
||||
app().registerWebSocketControllerRegex(
|
||||
regExp,
|
||||
WebSocketController<T, AutoCreation>::classTypeName(),
|
||||
constraints);
|
||||
}
|
||||
|
||||
private:
|
||||
class pathRegistrator
|
||||
{
|
||||
|
|
|
@ -294,6 +294,17 @@ HttpAppFramework &HttpAppFrameworkImpl::registerWebSocketController(
|
|||
return *this;
|
||||
}
|
||||
|
||||
HttpAppFramework &HttpAppFrameworkImpl::registerWebSocketControllerRegex(
|
||||
const std::string ®Exp,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &constraints)
|
||||
{
|
||||
assert(!routersInit_);
|
||||
HttpControllersRouter::instance().registerWebSocketControllerRegex(
|
||||
regExp, ctrlName, constraints);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAppFramework &HttpAppFrameworkImpl::registerHttpSimpleController(
|
||||
const std::string &pathName,
|
||||
const std::string &ctrlName,
|
||||
|
|
|
@ -89,6 +89,10 @@ class HttpAppFrameworkImpl final : public HttpAppFramework
|
|||
const std::string &pathName,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &constraints) override;
|
||||
HttpAppFramework ®isterWebSocketControllerRegex(
|
||||
const std::string ®Exp,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &constraints) override;
|
||||
HttpAppFramework ®isterHttpSimpleController(
|
||||
const std::string &pathName,
|
||||
const std::string &ctrlName,
|
||||
|
|
|
@ -105,7 +105,10 @@ std::vector<HttpHandlerInfo> HttpControllersRouter::getHandlersInfo() const
|
|||
}
|
||||
else if constexpr (std::is_same_v<
|
||||
std::decay_t<decltype(item)>,
|
||||
WebSocketControllerRouterItem>)
|
||||
WebSocketControllerRouterItem> ||
|
||||
std::is_same_v<
|
||||
std::decay_t<decltype(item)>,
|
||||
RegExWebSocketControllerRouterItem>)
|
||||
{
|
||||
description = std::string("WebsocketController: ") +
|
||||
item.binders_[i]->handlerName_;
|
||||
|
@ -140,6 +143,10 @@ std::vector<HttpHandlerInfo> HttpControllersRouter::getHandlersInfo() const
|
|||
{
|
||||
gatherInfo(path, item);
|
||||
}
|
||||
for (auto &item : wsCtrlVector_)
|
||||
{
|
||||
gatherInfo(item.pathPattern_, item);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -276,6 +283,30 @@ void HttpControllersRouter::registerWebSocketController(
|
|||
addCtrlBinderToRouterItem(binder, item, result.validMethods);
|
||||
}
|
||||
|
||||
void HttpControllersRouter::registerWebSocketControllerRegex(
|
||||
const std::string ®Exp,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &constraints)
|
||||
{
|
||||
assert(!regExp.empty());
|
||||
assert(!ctrlName.empty());
|
||||
auto result = processSimpleControllerParams(regExp, constraints);
|
||||
auto binder = std::make_shared<WebsocketControllerBinder>();
|
||||
binder->handlerName_ = ctrlName;
|
||||
binder->middlewareNames_ = result.middlewares;
|
||||
drogon::app().getLoop()->queueInLoop([binder, ctrlName]() {
|
||||
auto &object_ = DrClassMap::getSingleInstance(ctrlName);
|
||||
auto controller =
|
||||
std::dynamic_pointer_cast<WebSocketControllerBase>(object_);
|
||||
binder->controller_ = controller;
|
||||
});
|
||||
struct RegExWebSocketControllerRouterItem router;
|
||||
router.pathPattern_ = regExp;
|
||||
router.regex_ = regExp;
|
||||
addCtrlBinderToRouterItem(binder, router, result.validMethods);
|
||||
wsCtrlVector_.push_back(std::move(router));
|
||||
}
|
||||
|
||||
void HttpControllersRouter::addHttpRegex(
|
||||
const std::string ®Exp,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
|
@ -681,6 +712,24 @@ RouteResult HttpControllersRouter::routeWs(const HttpRequestImplPtr &req)
|
|||
}
|
||||
return {RouteResult::Success, binder};
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &ctrlInfo : wsCtrlVector_)
|
||||
{
|
||||
auto const &wsCtrlRegex = ctrlInfo.regex_;
|
||||
std::smatch result;
|
||||
if (std::regex_match(req->path(), result, wsCtrlRegex))
|
||||
{
|
||||
req->setMatchedPathPattern(ctrlInfo.pathPattern_);
|
||||
auto &binder = ctrlInfo.binders_[req->method()];
|
||||
if (!binder)
|
||||
{
|
||||
return {RouteResult::MethodNotAllowed, nullptr};
|
||||
}
|
||||
return {RouteResult::Success, binder};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {RouteResult::NotFound, nullptr};
|
||||
}
|
||||
|
|
|
@ -50,6 +50,10 @@ class HttpControllersRouter : public trantor::NonCopyable
|
|||
const std::string &pathName,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &constraints);
|
||||
void registerWebSocketControllerRegex(
|
||||
const std::string ®Exp,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<internal::HttpConstraint> &constraints);
|
||||
void addHttpPath(const std::string &path,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
const std::vector<HttpMethod> &validMethods,
|
||||
|
@ -89,9 +93,17 @@ class HttpControllersRouter : public trantor::NonCopyable
|
|||
std::shared_ptr<WebsocketControllerBinder> binders_[Invalid]{nullptr};
|
||||
};
|
||||
|
||||
struct RegExWebSocketControllerRouterItem
|
||||
{
|
||||
std::string pathPattern_;
|
||||
std::regex regex_;
|
||||
std::shared_ptr<WebsocketControllerBinder> binders_[Invalid]{nullptr};
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, SimpleControllerRouterItem> simpleCtrlMap_;
|
||||
std::unordered_map<std::string, HttpControllerRouterItem> ctrlMap_;
|
||||
std::vector<HttpControllerRouterItem> ctrlVector_; // for regexp path
|
||||
std::unordered_map<std::string, WebSocketControllerRouterItem> wsCtrlMap_;
|
||||
std::vector<RegExWebSocketControllerRouterItem> wsCtrlVector_;
|
||||
};
|
||||
} // namespace drogon
|
||||
|
|
Loading…
Reference in New Issue