2019-12-08 00:31:56 +00:00
|
|
|
/**
|
|
|
|
*
|
2020-08-25 00:07:43 +00:00
|
|
|
* @file SimpleReverseProxy.cc
|
2019-12-08 00:31:56 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "SimpleReverseProxy.h"
|
|
|
|
|
|
|
|
using namespace drogon;
|
|
|
|
using namespace my_plugin;
|
|
|
|
|
|
|
|
void SimpleReverseProxy::initAndStart(const Json::Value &config)
|
|
|
|
{
|
|
|
|
/// Initialize and start the plugin
|
|
|
|
if (config.isMember("backends") && config["backends"].isArray())
|
|
|
|
{
|
|
|
|
for (auto &backend : config["backends"])
|
|
|
|
{
|
|
|
|
backendAddrs_.emplace_back(backend.asString());
|
|
|
|
}
|
|
|
|
if (backendAddrs_.empty())
|
|
|
|
{
|
|
|
|
LOG_ERROR << "You must set at least one backend";
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_ERROR << "Error in configuration";
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
pipeliningDepth_ = config.get("pipelining", 0).asInt();
|
2019-12-15 16:34:40 +00:00
|
|
|
sameClientToSameBackend_ =
|
|
|
|
config.get("same_client_to_same_backend", false).asBool();
|
|
|
|
connectionFactor_ = config.get("connection_factor", 1).asInt();
|
|
|
|
if (connectionFactor_ == 0 || connectionFactor_ > 100)
|
2019-12-08 00:31:56 +00:00
|
|
|
{
|
2019-12-15 16:34:40 +00:00
|
|
|
LOG_ERROR << "invalid number of connection factor";
|
|
|
|
abort();
|
2019-12-08 00:31:56 +00:00
|
|
|
}
|
|
|
|
clients_.init(
|
|
|
|
[this](std::vector<HttpClientPtr> &clients, size_t ioLoopIndex) {
|
2019-12-15 16:34:40 +00:00
|
|
|
clients.resize(backendAddrs_.size() * connectionFactor_);
|
2019-12-08 00:31:56 +00:00
|
|
|
});
|
|
|
|
clientIndex_.init(
|
|
|
|
[this](size_t &index, size_t ioLoopIndex) { index = ioLoopIndex; });
|
|
|
|
drogon::app().registerPreRoutingAdvice([this](const HttpRequestPtr &req,
|
|
|
|
AdviceCallback &&callback,
|
|
|
|
AdviceChainCallback &&pass) {
|
|
|
|
preRouting(req, std::move(callback), std::move(pass));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleReverseProxy::shutdown()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleReverseProxy::preRouting(const HttpRequestPtr &req,
|
|
|
|
AdviceCallback &&callback,
|
|
|
|
AdviceChainCallback &&)
|
|
|
|
{
|
|
|
|
size_t index;
|
|
|
|
auto &clientsVector = *clients_;
|
|
|
|
if (sameClientToSameBackend_)
|
|
|
|
{
|
2019-12-15 16:34:40 +00:00
|
|
|
index = std::hash<uint32_t>{}(req->getPeerAddr().ipNetEndian()) %
|
|
|
|
clientsVector.size();
|
|
|
|
index = (index + (++(*clientIndex_)) * backendAddrs_.size()) %
|
|
|
|
clientsVector.size();
|
2019-12-08 00:31:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
index = ++(*clientIndex_) % clientsVector.size();
|
|
|
|
}
|
|
|
|
auto &clientPtr = clientsVector[index];
|
|
|
|
if (!clientPtr)
|
|
|
|
{
|
2019-12-15 16:34:40 +00:00
|
|
|
auto &addr = backendAddrs_[index % backendAddrs_.size()];
|
2019-12-08 00:31:56 +00:00
|
|
|
clientPtr = HttpClient::newHttpClient(
|
|
|
|
addr, trantor::EventLoop::getEventLoopOfCurrentThread());
|
|
|
|
clientPtr->setPipeliningDepth(pipeliningDepth_);
|
|
|
|
}
|
2019-12-15 16:34:40 +00:00
|
|
|
req->setPassThrough(true);
|
2019-12-08 00:31:56 +00:00
|
|
|
clientPtr->sendRequest(
|
|
|
|
req,
|
|
|
|
[callback = std::move(callback)](ReqResult result,
|
|
|
|
const HttpResponsePtr &resp) {
|
|
|
|
if (result == ReqResult::Ok)
|
|
|
|
{
|
2019-12-15 16:34:40 +00:00
|
|
|
resp->setPassThrough(true);
|
2019-12-08 00:31:56 +00:00
|
|
|
callback(resp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto errResp = HttpResponse::newHttpResponse();
|
|
|
|
errResp->setStatusCode(k500InternalServerError);
|
|
|
|
callback(errResp);
|
|
|
|
}
|
|
|
|
});
|
2024-01-31 02:43:30 +00:00
|
|
|
}
|