mirror of
https://gitee.com/an-tao/drogon.git
synced 2024-12-02 03:38:03 +08:00
Support coroutine filter. (#1352)
This commit is contained in:
parent
4ef31d7c2d
commit
bd9d290b82
@ -19,8 +19,7 @@
|
||||
#include <drogon/CacheMap.h>
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/HttpBinder.h>
|
||||
#include <drogon/IntranetIpFilter.h>
|
||||
#include <drogon/LocalHostFilter.h>
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include <drogon/MultiPart.h>
|
||||
#include <drogon/NotFound.h>
|
||||
#include <drogon/drogon_callbacks.h>
|
||||
|
@ -20,6 +20,10 @@
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <memory>
|
||||
|
||||
#ifdef __cpp_impl_coroutine
|
||||
#include <drogon/utils/coroutine.h>
|
||||
#endif
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
/**
|
||||
@ -43,9 +47,7 @@ class DROGON_EXPORT HttpFilterBase : public virtual DrObjectBase
|
||||
virtual void doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb) = 0;
|
||||
virtual ~HttpFilterBase()
|
||||
{
|
||||
}
|
||||
~HttpFilterBase() override = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -60,8 +62,61 @@ class HttpFilter : public DrObject<T>, public HttpFilterBase
|
||||
{
|
||||
public:
|
||||
static constexpr bool isAutoCreation{AutoCreation};
|
||||
virtual ~HttpFilter()
|
||||
{
|
||||
}
|
||||
~HttpFilter() override = default;
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
DROGON_EXPORT void handleException(
|
||||
const std::exception &,
|
||||
const HttpRequestPtr &,
|
||||
std::function<void(const HttpResponsePtr &)> &&);
|
||||
}
|
||||
|
||||
#ifdef __cpp_impl_coroutine
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class HttpCoroFilter : public DrObject<T>, public HttpFilterBase
|
||||
{
|
||||
public:
|
||||
static constexpr bool isAutoCreation{AutoCreation};
|
||||
~HttpCoroFilter() override = default;
|
||||
void doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb) final
|
||||
{
|
||||
drogon::async_run([this,
|
||||
req,
|
||||
fcb = std::move(fcb),
|
||||
fccb = std::move(fccb)]() mutable -> drogon::Task<> {
|
||||
HttpResponsePtr resp;
|
||||
try
|
||||
{
|
||||
resp = co_await doFilter(req);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
internal::handleException(ex, req, std::move(fcb));
|
||||
co_return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR << "Exception not derived from std::exception";
|
||||
co_return;
|
||||
}
|
||||
|
||||
if (resp)
|
||||
{
|
||||
fcb(resp);
|
||||
}
|
||||
else
|
||||
{
|
||||
fccb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
virtual Task<HttpResponsePtr> doFilter(const HttpRequestPtr &req) = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace drogon
|
||||
|
@ -72,6 +72,7 @@ if (BUILD_CTL)
|
||||
if(DROGON_CXX_STANDARD GREATER_EQUAL 20 AND HAS_COROUTINE)
|
||||
set(INTEGRATION_TEST_SERVER_SOURCES
|
||||
${INTEGRATION_TEST_SERVER_SOURCES}
|
||||
integration_test/server/CoroFilter.cpp
|
||||
integration_test/server/api_v1_CoroTest.cc)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <mutex>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
@ -1011,6 +1012,7 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
|
||||
CHECK(resp->getStatusCode() == k200OK);
|
||||
CHECK(resp->body() == largeString);
|
||||
});
|
||||
|
||||
#ifdef USE_BROTLI
|
||||
// Post compressed data
|
||||
req = HttpRequest::newHttpRequest();
|
||||
@ -1093,6 +1095,23 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
|
||||
{
|
||||
FAIL("Unexpected exception, what()" + std::string(e.what()));
|
||||
}
|
||||
|
||||
// Test coroutine filter
|
||||
try
|
||||
{
|
||||
auto req = HttpRequest::newHttpRequest();
|
||||
auto start = std::chrono::system_clock::now();
|
||||
req->setPath("/api/v1/corotest/delay?secs=2");
|
||||
auto resp = co_await client->sendRequestCoro(req);
|
||||
CHECK(resp->getStatusCode() == k200OK);
|
||||
auto end = std::chrono::system_clock::now();
|
||||
std::chrono::duration<double, std::milli> duration = end - start;
|
||||
CHECK(duration.count() >= 2000);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
FAIL("Unexpected exception, what()" + std::string(e.what()));
|
||||
}
|
||||
}());
|
||||
#endif
|
||||
}
|
||||
|
12
lib/tests/integration_test/server/CoroFilter.cpp
Normal file
12
lib/tests/integration_test/server/CoroFilter.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
//
|
||||
// Created by wanchen.he on 2022/8/16.
|
||||
//
|
||||
|
||||
#include "CoroFilter.h"
|
||||
|
||||
Task<HttpResponsePtr> CoroFilter::doFilter(const HttpRequestPtr& req)
|
||||
{
|
||||
int secs = std::stoi(req->getParameter("secs"));
|
||||
co_await sleepCoro(trantor::EventLoop::getEventLoopOfCurrentThread(), secs);
|
||||
co_return {};
|
||||
}
|
17
lib/tests/integration_test/server/CoroFilter.h
Normal file
17
lib/tests/integration_test/server/CoroFilter.h
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by wanchen.he on 2022/8/16.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <drogon/HttpFilter.h>
|
||||
using namespace drogon;
|
||||
|
||||
class CoroFilter : public drogon::HttpCoroFilter<CoroFilter>
|
||||
{
|
||||
public:
|
||||
Task<HttpResponsePtr> doFilter(const HttpRequestPtr &req) override;
|
||||
CoroFilter()
|
||||
{
|
||||
LOG_DEBUG << "CoroFilter constructor";
|
||||
}
|
||||
};
|
@ -11,6 +11,7 @@ class CoroTest : public drogon::HttpController<CoroTest>
|
||||
METHOD_LIST_BEGIN
|
||||
METHOD_ADD(CoroTest::get, "/get", Get);
|
||||
METHOD_ADD(CoroTest::get2, "/get2", Get);
|
||||
METHOD_ADD(CoroTest::get2, "/delay", Get, "CoroFilter");
|
||||
METHOD_ADD(CoroTest::this_will_fail, "/this_will_fail", Get);
|
||||
METHOD_ADD(CoroTest::this_will_fail2, "/this_will_fail2", Get);
|
||||
METHOD_LIST_END
|
||||
|
Loading…
Reference in New Issue
Block a user