mirror of
https://github.com/drogonframework/drogon.git
synced 2025-11-22 00:06:01 -05:00
Add some managers to reduce the size of the HttpAppFrameworkImpl code (#194)
This commit is contained in:
parent
b85d8c5a08
commit
9af87bb1c0
@ -32,7 +32,7 @@ void TimeFilter::doFilter(const HttpRequestPtr &req,
|
||||
{
|
||||
Json::Value json;
|
||||
json["result"] = "error";
|
||||
json["message"] = "Visit interval should be at least 10 seconds";
|
||||
json["message"] = "Access interval should be at least 10 seconds";
|
||||
auto res = HttpResponse::newHttpJsonResponse(json);
|
||||
cb(res);
|
||||
return;
|
||||
|
||||
@ -109,7 +109,7 @@ void doTest(const HttpClientPtr &client,
|
||||
auto &json = resp1->jsonObject();
|
||||
if (json && json->get("message", std::string(""))
|
||||
.asString() ==
|
||||
"Visit interval should be "
|
||||
"Access interval should be "
|
||||
"at least 10 "
|
||||
"seconds")
|
||||
{
|
||||
|
||||
@ -16,9 +16,6 @@
|
||||
#include "AOPAdvice.h"
|
||||
#include "ConfigLoader.h"
|
||||
#include "HttpServer.h"
|
||||
#if USE_ORM
|
||||
#include "../../orm_lib/src/DbClientLockFree.h"
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <drogon/CacheMap.h>
|
||||
#include <drogon/DrClassMap.h>
|
||||
@ -27,20 +24,22 @@
|
||||
#include <drogon/HttpTypes.h>
|
||||
#include <drogon/Session.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <fcntl.h>
|
||||
#include <trantor/utils/AsyncFileLogger.h>
|
||||
#include <json/json.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <json/json.h>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <trantor/utils/AsyncFileLogger.h>
|
||||
#include <tuple>
|
||||
#include <unistd.h>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <uuid.h>
|
||||
|
||||
using namespace drogon;
|
||||
@ -52,26 +51,7 @@ drogon::InitBeforeMainFunction drogon::HttpAppFrameworkImpl::_initFirst([]() {
|
||||
LOG_TRACE << "Initialize the main event loop in the main thread";
|
||||
});
|
||||
});
|
||||
namespace drogon
|
||||
{
|
||||
class DrogonFileLocker : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
DrogonFileLocker()
|
||||
{
|
||||
_fd = open("/tmp/drogon.lock", O_TRUNC | O_CREAT, 0755);
|
||||
flock(_fd, LOCK_EX);
|
||||
}
|
||||
~DrogonFileLocker()
|
||||
{
|
||||
close(_fd);
|
||||
}
|
||||
|
||||
private:
|
||||
int _fd = 0;
|
||||
};
|
||||
|
||||
} // namespace drogon
|
||||
static void godaemon(void)
|
||||
{
|
||||
printf("Initializing daemon mode\n");
|
||||
@ -218,23 +198,6 @@ void HttpAppFrameworkImpl::setSSLFiles(const std::string &certPath,
|
||||
_sslCertPath = certPath;
|
||||
_sslKeyPath = keyPath;
|
||||
}
|
||||
void HttpAppFrameworkImpl::addListener(const std::string &ip,
|
||||
uint16_t port,
|
||||
bool useSSL,
|
||||
const std::string &certFile,
|
||||
const std::string &keyFile)
|
||||
{
|
||||
assert(!_running);
|
||||
|
||||
#ifndef USE_OPENSSL
|
||||
if (useSSL)
|
||||
{
|
||||
LOG_ERROR << "Can't use SSL without OpenSSL found in your system";
|
||||
}
|
||||
#endif
|
||||
|
||||
_listeners.push_back(std::make_tuple(ip, port, useSSL, certFile, keyFile));
|
||||
}
|
||||
|
||||
void HttpAppFrameworkImpl::run()
|
||||
{
|
||||
@ -320,131 +283,20 @@ void HttpAppFrameworkImpl::run()
|
||||
_sharedLibManagerPtr = std::unique_ptr<SharedLibManager>(
|
||||
new SharedLibManager(getLoop(), _libFilePaths));
|
||||
}
|
||||
std::vector<std::shared_ptr<HttpServer>> servers;
|
||||
std::vector<std::shared_ptr<EventLoopThread>> loopThreads;
|
||||
|
||||
std::vector<trantor::EventLoop *> ioLoops;
|
||||
|
||||
#ifdef __linux__
|
||||
for (size_t i = 0; i < _threadNum; i++)
|
||||
{
|
||||
LOG_TRACE << "thread num=" << _threadNum;
|
||||
auto loopThreadPtr = std::make_shared<EventLoopThread>("DrogonIoLoop");
|
||||
loopThreads.push_back(loopThreadPtr);
|
||||
ioLoops.push_back(loopThreadPtr->getLoop());
|
||||
for (auto const &listener : _listeners)
|
||||
{
|
||||
auto ip = std::get<0>(listener);
|
||||
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
|
||||
std::shared_ptr<HttpServer> serverPtr;
|
||||
if (i == 0)
|
||||
{
|
||||
DrogonFileLocker lock;
|
||||
// Check whether the port is in use.
|
||||
TcpServer server(getLoop(),
|
||||
InetAddress(ip, std::get<1>(listener), isIpv6),
|
||||
"drogonPortTest",
|
||||
true,
|
||||
false);
|
||||
serverPtr = std::make_shared<HttpServer>(
|
||||
loopThreadPtr->getLoop(),
|
||||
InetAddress(ip, std::get<1>(listener), isIpv6),
|
||||
"drogon");
|
||||
}
|
||||
else
|
||||
{
|
||||
serverPtr = std::make_shared<HttpServer>(
|
||||
loopThreadPtr->getLoop(),
|
||||
InetAddress(ip, std::get<1>(listener), isIpv6),
|
||||
"drogon");
|
||||
}
|
||||
|
||||
if (std::get<2>(listener))
|
||||
{
|
||||
#ifdef USE_OPENSSL
|
||||
auto cert = std::get<3>(listener);
|
||||
auto key = std::get<4>(listener);
|
||||
if (cert == "")
|
||||
cert = _sslCertPath;
|
||||
if (key == "")
|
||||
key = _sslKeyPath;
|
||||
if (cert == "" || key == "")
|
||||
{
|
||||
std::cerr
|
||||
<< "You can't use https without cert file or key file"
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
serverPtr->enableSSL(cert, key);
|
||||
#endif
|
||||
}
|
||||
serverPtr->setHttpAsyncCallback(
|
||||
std::bind(&HttpAppFrameworkImpl::onAsyncRequest, this, _1, _2));
|
||||
serverPtr->setNewWebsocketCallback(std::bind(
|
||||
&HttpAppFrameworkImpl::onNewWebsockRequest, this, _1, _2, _3));
|
||||
serverPtr->setConnectionCallback(
|
||||
std::bind(&HttpAppFrameworkImpl::onConnection, this, _1));
|
||||
serverPtr->kickoffIdleConnections(_idleConnectionTimeout);
|
||||
serverPtr->start();
|
||||
servers.push_back(serverPtr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
auto loopThreadPtr =
|
||||
std::make_shared<EventLoopThread>("DrogonListeningLoop");
|
||||
loopThreads.push_back(loopThreadPtr);
|
||||
auto ioLoopThreadPoolPtr =
|
||||
std::make_shared<EventLoopThreadPool>(_threadNum);
|
||||
for (auto const &listener : _listeners)
|
||||
{
|
||||
LOG_TRACE << "thread num=" << _threadNum;
|
||||
auto ip = std::get<0>(listener);
|
||||
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
|
||||
auto serverPtr = std::make_shared<HttpServer>(
|
||||
loopThreadPtr->getLoop(),
|
||||
InetAddress(ip, std::get<1>(listener), isIpv6),
|
||||
"drogon");
|
||||
if (std::get<2>(listener))
|
||||
{
|
||||
#ifdef USE_OPENSSL
|
||||
auto cert = std::get<3>(listener);
|
||||
auto key = std::get<4>(listener);
|
||||
if (cert == "")
|
||||
cert = _sslCertPath;
|
||||
if (key == "")
|
||||
key = _sslKeyPath;
|
||||
if (cert == "" || key == "")
|
||||
{
|
||||
std::cerr << "You can't use https without cert file or key file"
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
serverPtr->enableSSL(cert, key);
|
||||
#endif
|
||||
}
|
||||
serverPtr->setIoLoopThreadPool(ioLoopThreadPoolPtr);
|
||||
serverPtr->setHttpAsyncCallback(
|
||||
std::bind(&HttpAppFrameworkImpl::onAsyncRequest, this, _1, _2));
|
||||
serverPtr->setNewWebsocketCallback(std::bind(
|
||||
&HttpAppFrameworkImpl::onNewWebsockRequest, this, _1, _2, _3));
|
||||
serverPtr->setConnectionCallback(
|
||||
std::bind(&HttpAppFrameworkImpl::onConnection, this, _1));
|
||||
serverPtr->kickoffIdleConnections(_idleConnectionTimeout);
|
||||
serverPtr->start();
|
||||
servers.push_back(serverPtr);
|
||||
}
|
||||
auto serverIoLoops = ioLoopThreadPoolPtr->getLoops();
|
||||
for (auto serverIoLoop : serverIoLoops)
|
||||
{
|
||||
ioLoops.push_back(serverIoLoop);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create all listeners.
|
||||
auto ioLoops = _listenerManager.createListeners(
|
||||
std::bind(&HttpAppFrameworkImpl::onAsyncRequest, this, _1, _2),
|
||||
std::bind(&HttpAppFrameworkImpl::onNewWebsockRequest, this, _1, _2, _3),
|
||||
std::bind(&HttpAppFrameworkImpl::onConnection, this, _1),
|
||||
_idleConnectionTimeout,
|
||||
_sslCertPath,
|
||||
_sslKeyPath,
|
||||
_threadNum);
|
||||
#if USE_ORM
|
||||
// A fast database client instance should be created in the main event loop,
|
||||
// so put the main loop into ioLoops.
|
||||
ioLoops.push_back(getLoop());
|
||||
createDbClients(ioLoops);
|
||||
_dbClientManager.createDbClients(ioLoops);
|
||||
ioLoops.pop_back();
|
||||
#endif
|
||||
_httpCtrlsRouter.init(ioLoops);
|
||||
@ -454,33 +306,8 @@ void HttpAppFrameworkImpl::run()
|
||||
|
||||
if (_useSession)
|
||||
{
|
||||
if (_sessionTimeout > 0)
|
||||
{
|
||||
size_t wheelNum = 1;
|
||||
size_t bucketNum = 0;
|
||||
if (_sessionTimeout < 500)
|
||||
{
|
||||
bucketNum = _sessionTimeout + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmpTimeout = _sessionTimeout;
|
||||
bucketNum = 100;
|
||||
while (tmpTimeout > 100)
|
||||
{
|
||||
wheelNum++;
|
||||
tmpTimeout = tmpTimeout / 100;
|
||||
}
|
||||
}
|
||||
_sessionMapPtr = std::unique_ptr<CacheMap<std::string, SessionPtr>>(
|
||||
new CacheMap<std::string, SessionPtr>(
|
||||
getLoop(), 1.0, wheelNum, bucketNum));
|
||||
}
|
||||
else if (_sessionTimeout == 0)
|
||||
{
|
||||
_sessionMapPtr = std::unique_ptr<CacheMap<std::string, SessionPtr>>(
|
||||
new CacheMap<std::string, SessionPtr>(getLoop(), 0, 0, 0));
|
||||
}
|
||||
_sessionManagerPtr = std::unique_ptr<SessionManager>(
|
||||
new SessionManager(getLoop(), _sessionTimeout));
|
||||
}
|
||||
|
||||
// Initialize plugins
|
||||
@ -494,74 +321,11 @@ void HttpAppFrameworkImpl::run()
|
||||
}
|
||||
|
||||
// Let listener event loops run when everything is ready.
|
||||
for (auto &loopTh : loopThreads)
|
||||
{
|
||||
loopTh->run();
|
||||
}
|
||||
_listenerManager.startListening();
|
||||
getLoop()->loop();
|
||||
}
|
||||
#if USE_ORM
|
||||
void HttpAppFrameworkImpl::createDbClients(
|
||||
const std::vector<trantor::EventLoop *> &ioloops)
|
||||
{
|
||||
assert(_dbClientsMap.empty());
|
||||
assert(_dbFastClientsMap.empty());
|
||||
for (auto &dbInfo : _dbInfos)
|
||||
{
|
||||
if (dbInfo._isFast)
|
||||
{
|
||||
for (auto *loop : ioloops)
|
||||
{
|
||||
if (dbInfo._dbType == drogon::orm::ClientType::Sqlite3)
|
||||
{
|
||||
LOG_ERROR << "Sqlite3 don't support fast mode";
|
||||
abort();
|
||||
}
|
||||
if (dbInfo._dbType == drogon::orm::ClientType::PostgreSQL ||
|
||||
dbInfo._dbType == drogon::orm::ClientType::Mysql)
|
||||
{
|
||||
_dbFastClientsMap[dbInfo._name][loop] =
|
||||
std::shared_ptr<drogon::orm::DbClient>(
|
||||
new drogon::orm::DbClientLockFree(
|
||||
dbInfo._connectionInfo,
|
||||
loop,
|
||||
dbInfo._dbType,
|
||||
dbInfo._connectionNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dbInfo._dbType == drogon::orm::ClientType::PostgreSQL)
|
||||
{
|
||||
#if USE_POSTGRESQL
|
||||
_dbClientsMap[dbInfo._name] =
|
||||
drogon::orm::DbClient::newPgClient(
|
||||
dbInfo._connectionInfo, dbInfo._connectionNumber);
|
||||
#endif
|
||||
}
|
||||
else if (dbInfo._dbType == drogon::orm::ClientType::Mysql)
|
||||
{
|
||||
#if USE_MYSQL
|
||||
_dbClientsMap[dbInfo._name] =
|
||||
drogon::orm::DbClient::newMysqlClient(
|
||||
dbInfo._connectionInfo, dbInfo._connectionNumber);
|
||||
#endif
|
||||
}
|
||||
else if (dbInfo._dbType == drogon::orm::ClientType::Sqlite3)
|
||||
{
|
||||
#if USE_SQLITE3
|
||||
_dbClientsMap[dbInfo._name] =
|
||||
drogon::orm::DbClient::newSqlite3Client(
|
||||
dbInfo._connectionInfo, dbInfo._connectionNumber);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void HttpAppFrameworkImpl::onConnection(const TcpConnectionPtr &conn)
|
||||
void HttpAppFrameworkImpl::onConnection(const trantor::TcpConnectionPtr &conn)
|
||||
{
|
||||
static std::mutex mtx;
|
||||
LOG_TRACE << "connect!!!" << _maxConnectionNum
|
||||
@ -691,25 +455,12 @@ void HttpAppFrameworkImpl::onAsyncRequest(
|
||||
bool needSetJsessionid = false;
|
||||
if (_useSession)
|
||||
{
|
||||
if (sessionId == "")
|
||||
if (sessionId.empty())
|
||||
{
|
||||
sessionId = utils::getUuid().c_str();
|
||||
needSetJsessionid = true;
|
||||
_sessionMapPtr->insert(sessionId,
|
||||
std::make_shared<Session>(),
|
||||
_sessionTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_sessionMapPtr->find(sessionId) == false)
|
||||
{
|
||||
_sessionMapPtr->insert(sessionId,
|
||||
std::make_shared<Session>(),
|
||||
_sessionTimeout);
|
||||
}
|
||||
}
|
||||
(std::dynamic_pointer_cast<HttpRequestImpl>(req))
|
||||
->setSession((*_sessionMapPtr)[sessionId]);
|
||||
req->setSession(_sessionManagerPtr->getSession(sessionId));
|
||||
}
|
||||
|
||||
// Route to controller
|
||||
@ -773,93 +524,6 @@ HttpAppFramework::~HttpAppFramework()
|
||||
{
|
||||
}
|
||||
|
||||
#if USE_ORM
|
||||
orm::DbClientPtr HttpAppFrameworkImpl::getDbClient(const std::string &name)
|
||||
{
|
||||
assert(_dbClientsMap.find(name) != _dbClientsMap.end());
|
||||
return _dbClientsMap[name];
|
||||
}
|
||||
orm::DbClientPtr HttpAppFrameworkImpl::getFastDbClient(const std::string &name)
|
||||
{
|
||||
assert(_dbFastClientsMap[name].find(
|
||||
trantor::EventLoop::getEventLoopOfCurrentThread()) !=
|
||||
_dbFastClientsMap[name].end());
|
||||
return _dbFastClientsMap[name]
|
||||
[trantor::EventLoop::getEventLoopOfCurrentThread()];
|
||||
}
|
||||
void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
|
||||
const std::string &host,
|
||||
const u_short port,
|
||||
const std::string &databaseName,
|
||||
const std::string &userName,
|
||||
const std::string &password,
|
||||
const size_t connectionNum,
|
||||
const std::string &filename,
|
||||
const std::string &name,
|
||||
const bool isFast)
|
||||
{
|
||||
assert(!_running);
|
||||
auto connStr = utils::formattedString("host=%s port=%u dbname=%s user=%s",
|
||||
host.c_str(),
|
||||
port,
|
||||
databaseName.c_str(),
|
||||
userName.c_str());
|
||||
if (!password.empty())
|
||||
{
|
||||
connStr += " password=";
|
||||
connStr += password;
|
||||
}
|
||||
std::string type = dbType;
|
||||
std::transform(type.begin(), type.end(), type.begin(), tolower);
|
||||
DbInfo info;
|
||||
info._connectionInfo = connStr;
|
||||
info._connectionNumber = connectionNum;
|
||||
info._isFast = isFast;
|
||||
info._name = name;
|
||||
|
||||
if (type == "postgresql")
|
||||
{
|
||||
#if USE_POSTGRESQL
|
||||
info._dbType = orm::ClientType::PostgreSQL;
|
||||
_dbInfos.push_back(info);
|
||||
#else
|
||||
std::cout
|
||||
<< "The PostgreSQL is not supported by drogon, please install "
|
||||
"the development library first."
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
else if (type == "mysql")
|
||||
{
|
||||
#if USE_MYSQL
|
||||
info._dbType = orm::ClientType::Mysql;
|
||||
_dbInfos.push_back(info);
|
||||
#else
|
||||
std::cout << "The Mysql is not supported by drogon, please install the "
|
||||
"development library first."
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
else if (type == "sqlite3")
|
||||
{
|
||||
#if USE_SQLITE3
|
||||
std::string sqlite3ConnStr = "filename=" + filename;
|
||||
info._connectionInfo = sqlite3ConnStr;
|
||||
info._dbType = orm::ClientType::Sqlite3;
|
||||
_dbInfos.push_back(info);
|
||||
#else
|
||||
std::cout
|
||||
<< "The Sqlite3 is not supported by drogon, please install the "
|
||||
"development library first."
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void HttpAppFrameworkImpl::forward(
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
|
||||
@ -20,11 +20,15 @@
|
||||
#include "HttpResponseImpl.h"
|
||||
#include "HttpSimpleControllersRouter.h"
|
||||
#include "PluginsManager.h"
|
||||
#include "ListenerManager.h"
|
||||
#include "SharedLibManager.h"
|
||||
#include "WebSocketConnectionImpl.h"
|
||||
#include "WebsocketControllersRouter.h"
|
||||
#include "StaticFileRouter.h"
|
||||
|
||||
#include "SessionManager.h"
|
||||
#if USE_ORM
|
||||
#include "../../orm_lib/src/DbClientManager.h"
|
||||
#endif
|
||||
#include <drogon/HttpAppFramework.h>
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
#include <drogon/version.h>
|
||||
@ -81,7 +85,11 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
uint16_t port,
|
||||
bool useSSL = false,
|
||||
const std::string &certFile = "",
|
||||
const std::string &keyFile = "") override;
|
||||
const std::string &keyFile = "") override
|
||||
{
|
||||
assert(!_running);
|
||||
_listenerManager.addListener(ip, port, useSSL, certFile, keyFile);
|
||||
}
|
||||
virtual void setThreadNum(size_t threadNum) override;
|
||||
virtual size_t getThreadNum() const override
|
||||
{
|
||||
@ -308,7 +316,7 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
{
|
||||
// Destroy the following objects before _loop destruction
|
||||
_sharedLibManagerPtr.reset();
|
||||
_sessionMapPtr.reset();
|
||||
_sessionManagerPtr.reset();
|
||||
}
|
||||
|
||||
virtual bool isRunning() override
|
||||
@ -338,9 +346,15 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
|
||||
#if USE_ORM
|
||||
virtual orm::DbClientPtr getDbClient(
|
||||
const std::string &name = "default") override;
|
||||
const std::string &name = "default") override
|
||||
{
|
||||
return _dbClientManager.getDbClient(name);
|
||||
}
|
||||
virtual orm::DbClientPtr getFastDbClient(
|
||||
const std::string &name = "default") override;
|
||||
const std::string &name = "default") override
|
||||
{
|
||||
return _dbClientManager.getFastDbClient(name);
|
||||
}
|
||||
virtual void createDbClient(const std::string &dbType,
|
||||
const std::string &host,
|
||||
const u_short port,
|
||||
@ -350,7 +364,20 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
const size_t connectionNum = 1,
|
||||
const std::string &filename = "",
|
||||
const std::string &name = "default",
|
||||
const bool isFast = false) override;
|
||||
const bool isFast = false) override
|
||||
{
|
||||
assert(!_running);
|
||||
_dbClientManager.createDbClient(dbType,
|
||||
host,
|
||||
port,
|
||||
databaseName,
|
||||
userName,
|
||||
password,
|
||||
connectionNum,
|
||||
filename,
|
||||
name,
|
||||
isFast);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline static HttpAppFrameworkImpl &instance()
|
||||
@ -377,7 +404,7 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
const WebSocketConnectionImplPtr &wsConnPtr);
|
||||
void onConnection(const TcpConnectionPtr &conn);
|
||||
void onConnection(const trantor::TcpConnectionPtr &conn);
|
||||
void addHttpPath(const std::string &path,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
const std::vector<HttpMethod> &validMethods,
|
||||
@ -389,15 +416,10 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
size_t _sessionTimeout = 0;
|
||||
size_t _idleConnectionTimeout = 60;
|
||||
bool _useSession = false;
|
||||
std::vector<
|
||||
std::tuple<std::string, uint16_t, bool, std::string, std::string>>
|
||||
_listeners;
|
||||
ListenerManager _listenerManager;
|
||||
std::string _serverHeader =
|
||||
"Server: drogon/" + drogon::getVersion() + "\r\n";
|
||||
|
||||
typedef std::shared_ptr<Session> SessionPtr;
|
||||
std::unique_ptr<CacheMap<std::string, SessionPtr>> _sessionMapPtr;
|
||||
|
||||
HttpControllersRouter _httpCtrlsRouter;
|
||||
HttpSimpleControllersRouter _httpSimpleCtrlsRouter;
|
||||
StaticFileRouter _staticFileRouter;
|
||||
@ -434,25 +456,13 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
size_t _clientMaxMemoryBodySize = 64 * 1024;
|
||||
size_t _clientMaxWebSocketMessageSize = 128 * 1024;
|
||||
std::string _homePageFile = "index.html";
|
||||
|
||||
std::unique_ptr<SessionManager> _sessionManagerPtr;
|
||||
// Json::Value _customConfig;
|
||||
Json::Value _jsonConfig;
|
||||
PluginsManager _pluginsManager;
|
||||
HttpResponsePtr _custom404;
|
||||
#if USE_ORM
|
||||
std::map<std::string, orm::DbClientPtr> _dbClientsMap;
|
||||
struct DbInfo
|
||||
{
|
||||
std::string _name;
|
||||
std::string _connectionInfo;
|
||||
orm::ClientType _dbType;
|
||||
bool _isFast;
|
||||
size_t _connectionNumber;
|
||||
};
|
||||
std::vector<DbInfo> _dbInfos;
|
||||
std::map<std::string, std::map<trantor::EventLoop *, orm::DbClientPtr>>
|
||||
_dbFastClientsMap;
|
||||
void createDbClients(const std::vector<trantor::EventLoop *> &ioloops);
|
||||
orm::DbClientManager _dbClientManager;
|
||||
#endif
|
||||
static InitBeforeMainFunction _initFirst;
|
||||
std::vector<std::function<bool(const trantor::InetAddress &,
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace trantor;
|
||||
using namespace drogon;
|
||||
using namespace std::placeholders;
|
||||
|
||||
|
||||
@ -102,7 +102,7 @@ void HttpRequestImpl::parseParameters() const
|
||||
// }
|
||||
}
|
||||
|
||||
void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
|
||||
void HttpRequestImpl::appendToBuffer(trantor::MsgBuffer *output) const
|
||||
{
|
||||
switch (_method)
|
||||
{
|
||||
|
||||
@ -34,9 +34,6 @@
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
using std::string;
|
||||
using namespace trantor;
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
class HttpRequestImpl : public HttpRequest
|
||||
@ -289,7 +286,7 @@ class HttpRequestImpl : public HttpRequest
|
||||
_cookies[key] = value;
|
||||
}
|
||||
|
||||
void appendToBuffer(MsgBuffer *output) const;
|
||||
void appendToBuffer(trantor::MsgBuffer *output) const;
|
||||
|
||||
virtual SessionPtr session() const override
|
||||
{
|
||||
|
||||
@ -22,7 +22,6 @@
|
||||
#include <trantor/net/TcpConnection.h>
|
||||
#include <trantor/utils/MsgBuffer.h>
|
||||
|
||||
using namespace trantor;
|
||||
namespace drogon
|
||||
{
|
||||
class HttpRequestParser
|
||||
@ -40,7 +39,7 @@ class HttpRequestParser
|
||||
explicit HttpRequestParser(const trantor::TcpConnectionPtr &connPtr);
|
||||
|
||||
// return false if any error
|
||||
bool parseRequest(MsgBuffer *buf);
|
||||
bool parseRequest(trantor::MsgBuffer *buf);
|
||||
|
||||
bool gotAll() const
|
||||
{
|
||||
|
||||
@ -26,7 +26,6 @@
|
||||
#include <trantor/utils/MsgBuffer.h>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace trantor;
|
||||
namespace drogon
|
||||
{
|
||||
class HttpResponseImpl : public HttpResponse
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
#include <trantor/net/TcpConnection.h>
|
||||
#include <trantor/utils/MsgBuffer.h>
|
||||
|
||||
using namespace trantor;
|
||||
namespace drogon
|
||||
{
|
||||
class HttpResponseParser
|
||||
@ -44,7 +43,7 @@ class HttpResponseParser
|
||||
// default copy-ctor, dtor and assignment are fine
|
||||
|
||||
// return false if any error
|
||||
bool parseResponse(MsgBuffer *buf);
|
||||
bool parseResponse(trantor::MsgBuffer *buf);
|
||||
|
||||
bool gotAll() const
|
||||
{
|
||||
|
||||
@ -24,30 +24,28 @@
|
||||
#include <trantor/net/callbacks.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
|
||||
using namespace trantor;
|
||||
namespace drogon
|
||||
{
|
||||
class HttpRequest;
|
||||
class HttpResponse;
|
||||
typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
|
||||
typedef std::function<void(const HttpRequestImplPtr &,
|
||||
std::function<void(const HttpResponsePtr &)> &&)>
|
||||
HttpAsyncCallback;
|
||||
typedef std::function<void(const HttpRequestImplPtr &,
|
||||
std::function<void(const HttpResponsePtr &)> &&,
|
||||
const WebSocketConnectionImplPtr &)>
|
||||
WebSocketNewAsyncCallback;
|
||||
class HttpServer : trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(const HttpRequestImplPtr &,
|
||||
std::function<void(const HttpResponsePtr &)> &&)>
|
||||
HttpAsyncCallback;
|
||||
typedef std::function<void(const HttpRequestImplPtr &,
|
||||
std::function<void(const HttpResponsePtr &)> &&,
|
||||
const WebSocketConnectionImplPtr &)>
|
||||
WebSocketNewAsyncCallback;
|
||||
|
||||
HttpServer(EventLoop *loop,
|
||||
const InetAddress &listenAddr,
|
||||
HttpServer(trantor::EventLoop *loop,
|
||||
const trantor::InetAddress &listenAddr,
|
||||
const std::string &name);
|
||||
|
||||
~HttpServer();
|
||||
|
||||
EventLoop *getLoop() const
|
||||
trantor::EventLoop *getLoop() const
|
||||
{
|
||||
return _server.getLoop();
|
||||
}
|
||||
@ -60,7 +58,7 @@ class HttpServer : trantor::NonCopyable
|
||||
{
|
||||
_newWebsocketCallback = cb;
|
||||
}
|
||||
void setConnectionCallback(const ConnectionCallback &cb)
|
||||
void setConnectionCallback(const trantor::ConnectionCallback &cb)
|
||||
{
|
||||
_connectionCallback = cb;
|
||||
}
|
||||
@ -95,10 +93,11 @@ class HttpServer : trantor::NonCopyable
|
||||
#endif
|
||||
|
||||
private:
|
||||
void onConnection(const TcpConnectionPtr &conn);
|
||||
void onMessage(const TcpConnectionPtr &, MsgBuffer *);
|
||||
void onRequest(const TcpConnectionPtr &, const HttpRequestImplPtr &);
|
||||
void sendResponse(const TcpConnectionPtr &,
|
||||
void onConnection(const trantor::TcpConnectionPtr &conn);
|
||||
void onMessage(const trantor::TcpConnectionPtr &, trantor::MsgBuffer *);
|
||||
void onRequest(const trantor::TcpConnectionPtr &,
|
||||
const HttpRequestImplPtr &);
|
||||
void sendResponse(const trantor::TcpConnectionPtr &,
|
||||
const HttpResponsePtr &,
|
||||
bool isHeadMethod);
|
||||
trantor::TcpServer _server;
|
||||
|
||||
187
lib/src/ListenerManager.cc
Normal file
187
lib/src/ListenerManager.cc
Normal file
@ -0,0 +1,187 @@
|
||||
/**
|
||||
*
|
||||
* ListenerManager.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 "ListenerManager.h"
|
||||
#include <trantor/utils/config.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
class DrogonFileLocker : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
DrogonFileLocker()
|
||||
{
|
||||
_fd = open("/tmp/drogon.lock", O_TRUNC | O_CREAT, 0755);
|
||||
flock(_fd, LOCK_EX);
|
||||
}
|
||||
~DrogonFileLocker()
|
||||
{
|
||||
close(_fd);
|
||||
}
|
||||
|
||||
private:
|
||||
int _fd = 0;
|
||||
};
|
||||
|
||||
} // namespace drogon
|
||||
|
||||
using namespace trantor;
|
||||
using namespace drogon;
|
||||
|
||||
void ListenerManager::addListener(const std::string &ip,
|
||||
uint16_t port,
|
||||
bool useSSL,
|
||||
const std::string &certFile,
|
||||
const std::string &keyFile)
|
||||
{
|
||||
#ifndef USE_OPENSSL
|
||||
if (useSSL)
|
||||
{
|
||||
LOG_ERROR << "Can't use SSL without OpenSSL found in your system";
|
||||
}
|
||||
#endif
|
||||
_listeners.emplace_back(ip, port, useSSL, certFile, keyFile);
|
||||
}
|
||||
|
||||
std::vector<trantor::EventLoop *> ListenerManager::createListeners(
|
||||
const HttpAsyncCallback &httpCallback,
|
||||
const WebSocketNewAsyncCallback &webSocketCallback,
|
||||
const ConnectionCallback &connectionCallback,
|
||||
size_t connectionTimeout,
|
||||
const std::string &globalCertFile,
|
||||
const std::string &globalKeyFile,
|
||||
size_t threadNum)
|
||||
{
|
||||
#ifdef __linux__
|
||||
std::vector<trantor::EventLoop *> ioLoops;
|
||||
for (size_t i = 0; i < threadNum; i++)
|
||||
{
|
||||
LOG_TRACE << "thread num=" << threadNum;
|
||||
auto loopThreadPtr = std::make_shared<EventLoopThread>("DrogonIoLoop");
|
||||
_listeningloopThreads.push_back(loopThreadPtr);
|
||||
ioLoops.push_back(loopThreadPtr->getLoop());
|
||||
for (auto const &listener : _listeners)
|
||||
{
|
||||
auto const &ip = listener._ip;
|
||||
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
|
||||
std::shared_ptr<HttpServer> serverPtr;
|
||||
if (i == 0)
|
||||
{
|
||||
DrogonFileLocker lock;
|
||||
// Check whether the port is in use.
|
||||
TcpServer server(app().getLoop(),
|
||||
InetAddress(ip, listener._port, isIpv6),
|
||||
"drogonPortTest",
|
||||
true,
|
||||
false);
|
||||
serverPtr = std::make_shared<HttpServer>(
|
||||
loopThreadPtr->getLoop(),
|
||||
InetAddress(ip, listener._port, isIpv6),
|
||||
"drogon");
|
||||
}
|
||||
else
|
||||
{
|
||||
serverPtr = std::make_shared<HttpServer>(
|
||||
loopThreadPtr->getLoop(),
|
||||
InetAddress(ip, listener._port, isIpv6),
|
||||
"drogon");
|
||||
}
|
||||
|
||||
if (listener._useSSL)
|
||||
{
|
||||
#ifdef USE_OPENSSL
|
||||
auto cert = listener._certFile;
|
||||
auto key = listener._keyFile;
|
||||
if (cert == "")
|
||||
cert = globalCertFile;
|
||||
if (key == "")
|
||||
key = globalKeyFile;
|
||||
if (cert == "" || key == "")
|
||||
{
|
||||
std::cerr
|
||||
<< "You can't use https without cert file or key file"
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
serverPtr->enableSSL(cert, key);
|
||||
#endif
|
||||
}
|
||||
serverPtr->setHttpAsyncCallback(httpCallback);
|
||||
serverPtr->setNewWebsocketCallback(webSocketCallback);
|
||||
serverPtr->setConnectionCallback(connectionCallback);
|
||||
serverPtr->kickoffIdleConnections(connectionTimeout);
|
||||
serverPtr->start();
|
||||
_servers.push_back(serverPtr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
auto loopThreadPtr =
|
||||
std::make_shared<EventLoopThread>("DrogonListeningLoop");
|
||||
_listeningloopThreads.push_back(loopThreadPtr);
|
||||
_ioLoopThreadPoolPtr = std::make_shared<EventLoopThreadPool>(threadNum);
|
||||
for (auto const &listener : _listeners)
|
||||
{
|
||||
LOG_TRACE << "thread num=" << threadNum;
|
||||
auto ip = listener._ip;
|
||||
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
|
||||
auto serverPtr = std::make_shared<HttpServer>(
|
||||
loopThreadPtr->getLoop(),
|
||||
InetAddress(ip, listener._port, isIpv6),
|
||||
"drogon");
|
||||
if (listener._useSSL)
|
||||
{
|
||||
#ifdef USE_OPENSSL
|
||||
auto cert = listener._certFile;
|
||||
auto key = listener._keyFile;
|
||||
if (cert == "")
|
||||
cert = globalCertFile;
|
||||
if (key == "")
|
||||
key = globalKeyFile;
|
||||
if (cert == "" || key == "")
|
||||
{
|
||||
std::cerr << "You can't use https without cert file or key file"
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
serverPtr->enableSSL(cert, key);
|
||||
#endif
|
||||
}
|
||||
serverPtr->setIoLoopThreadPool(_ioLoopThreadPoolPtr);
|
||||
serverPtr->setHttpAsyncCallback(httpCallback);
|
||||
serverPtr->setNewWebsocketCallback(webSocketCallback);
|
||||
serverPtr->setConnectionCallback(connectionCallback);
|
||||
serverPtr->kickoffIdleConnections(connectionTimeout);
|
||||
serverPtr->start();
|
||||
_servers.push_back(serverPtr);
|
||||
}
|
||||
auto ioLoops = _ioLoopThreadPoolPtr->getLoops();
|
||||
#endif
|
||||
return ioLoops;
|
||||
}
|
||||
|
||||
void ListenerManager::startListening()
|
||||
{
|
||||
for (auto &loopThread : _listeningloopThreads)
|
||||
{
|
||||
loopThread->run();
|
||||
}
|
||||
}
|
||||
73
lib/src/ListenerManager.h
Normal file
73
lib/src/ListenerManager.h
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
*
|
||||
* ListenerManager.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 "HttpServer.h"
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <trantor/net/EventLoopThread.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
class ListenerManager : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
void addListener(const std::string &ip,
|
||||
uint16_t port,
|
||||
bool useSSL = false,
|
||||
const std::string &certFile = "",
|
||||
const std::string &keyFile = "");
|
||||
std::vector<trantor::EventLoop *> createListeners(
|
||||
const HttpAsyncCallback &httpCallback,
|
||||
const WebSocketNewAsyncCallback &webSocketCallback,
|
||||
const trantor::ConnectionCallback &connectionCallback,
|
||||
size_t connectionTimeout,
|
||||
const std::string &globalCertFile,
|
||||
const std::string &globalKeyFile,
|
||||
size_t threadNum);
|
||||
void startListening();
|
||||
|
||||
private:
|
||||
struct ListenerInfo
|
||||
{
|
||||
ListenerInfo(const std::string &ip,
|
||||
uint16_t port,
|
||||
bool useSSL,
|
||||
const std::string &certFile,
|
||||
const std::string &keyFile)
|
||||
: _ip(ip),
|
||||
_port(port),
|
||||
_useSSL(useSSL),
|
||||
_certFile(certFile),
|
||||
_keyFile(keyFile)
|
||||
{
|
||||
}
|
||||
std::string _ip;
|
||||
uint16_t _port;
|
||||
bool _useSSL;
|
||||
std::string _certFile;
|
||||
std::string _keyFile;
|
||||
};
|
||||
std::vector<ListenerInfo> _listeners;
|
||||
std::vector<std::shared_ptr<HttpServer>> _servers;
|
||||
std::vector<std::shared_ptr<trantor::EventLoopThread>> _listeningloopThreads;
|
||||
std::string _sslCertPath;
|
||||
std::string _sslKeyPath;
|
||||
std::shared_ptr<trantor::EventLoopThreadPool> _ioLoopThreadPoolPtr;
|
||||
};
|
||||
|
||||
} // namespace drogon
|
||||
64
lib/src/SessionManager.cc
Normal file
64
lib/src/SessionManager.cc
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
*
|
||||
* SessionManager.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 "SessionManager.h"
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
SessionManager::SessionManager(trantor::EventLoop *loop, size_t timeout)
|
||||
: _loop(loop), _timeout(timeout)
|
||||
{
|
||||
assert(_timeout >= 0);
|
||||
if (_timeout > 0)
|
||||
{
|
||||
size_t wheelNum = 1;
|
||||
size_t bucketNum = 0;
|
||||
if (_timeout < 500)
|
||||
{
|
||||
bucketNum = _timeout + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmpTimeout = _timeout;
|
||||
bucketNum = 100;
|
||||
while (tmpTimeout > 100)
|
||||
{
|
||||
wheelNum++;
|
||||
tmpTimeout = tmpTimeout / 100;
|
||||
}
|
||||
}
|
||||
_sessionMapPtr = std::unique_ptr<CacheMap<std::string, SessionPtr>>(
|
||||
new CacheMap<std::string, SessionPtr>(
|
||||
_loop, 1.0, wheelNum, bucketNum));
|
||||
}
|
||||
else if (_timeout == 0)
|
||||
{
|
||||
_sessionMapPtr = std::unique_ptr<CacheMap<std::string, SessionPtr>>(
|
||||
new CacheMap<std::string, SessionPtr>(_loop, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
SessionPtr SessionManager::getSession(const std::string &sessionID)
|
||||
{
|
||||
assert(!sessionID.empty());
|
||||
SessionPtr sessionPtr;
|
||||
std::lock_guard<std::mutex> lock(_mapMutex);
|
||||
if (_sessionMapPtr->findAndFetch(sessionID, sessionPtr) == false)
|
||||
{
|
||||
sessionPtr = std::make_shared<Session>();
|
||||
_sessionMapPtr->insert(sessionID, sessionPtr, _timeout);
|
||||
return sessionPtr;
|
||||
}
|
||||
return sessionPtr;
|
||||
}
|
||||
44
lib/src/SessionManager.h
Normal file
44
lib/src/SessionManager.h
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
*
|
||||
* SessionManager.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 <trantor/utils/NonCopyable.h>
|
||||
#include <trantor/net/EventLoop.h>
|
||||
#include <drogon/Session.h>
|
||||
#include <drogon/CacheMap.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
class SessionManager : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
SessionManager(trantor::EventLoop *loop, size_t timeout);
|
||||
~SessionManager()
|
||||
{
|
||||
_sessionMapPtr.reset();
|
||||
}
|
||||
SessionPtr getSession(const std::string &sessionID);
|
||||
|
||||
private:
|
||||
std::unique_ptr<CacheMap<std::string, SessionPtr>> _sessionMapPtr;
|
||||
std::mutex _mapMutex;
|
||||
trantor::EventLoop *_loop;
|
||||
size_t _timeout;
|
||||
};
|
||||
} // namespace drogon
|
||||
@ -42,7 +42,7 @@ class DbClient : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
virtual ~DbClient(){};
|
||||
/// Create new database client with multiple connections;
|
||||
/// Create a new database client with multiple connections;
|
||||
/**
|
||||
* @param connInfo: Connection string with some parameters,
|
||||
* each parameter setting is in the form keyword = value. Spaces around the
|
||||
@ -163,12 +163,13 @@ class DbClient : public trantor::NonCopyable
|
||||
/**
|
||||
* @param commitCallback: the callback with which user can get the
|
||||
* submitting result, The Boolean type parameter in the callback function
|
||||
* indicates whether the transaction was submitted successfully. NOTE: The
|
||||
* callback only indicates the result of the 'commit' command, which is the
|
||||
* last step of the transaction. If the transaction has been automatically
|
||||
* or manually rolled back, the callback will never be executed. You can
|
||||
* also use the setCommitCallback() method of a transaction object to set
|
||||
* the callback.
|
||||
* indicates whether the transaction was submitted successfully.
|
||||
*
|
||||
* NOTE: The callback only indicates the result of the 'commit' command,
|
||||
* which is the last step of the transaction. If the transaction has been
|
||||
* automatically or manually rolled back, the callback will never be
|
||||
* executed. You can also use the setCommitCallback() method of a
|
||||
* transaction object to set the callback.
|
||||
*/
|
||||
virtual std::shared_ptr<Transaction> newTransaction(
|
||||
const std::function<void(bool)> &commitCallback = nullptr) = 0;
|
||||
|
||||
151
orm_lib/src/DbClientManager.cc
Normal file
151
orm_lib/src/DbClientManager.cc
Normal file
@ -0,0 +1,151 @@
|
||||
/**
|
||||
*
|
||||
* DbClientManager.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 "DbClientManager.h"
|
||||
#include "DbClientLockFree.h"
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace drogon::orm;
|
||||
using namespace drogon;
|
||||
|
||||
void DbClientManager::createDbClients(
|
||||
const std::vector<trantor::EventLoop *> &ioloops)
|
||||
{
|
||||
assert(_dbClientsMap.empty());
|
||||
assert(_dbFastClientsMap.empty());
|
||||
for (auto &dbInfo : _dbInfos)
|
||||
{
|
||||
if (dbInfo._isFast)
|
||||
{
|
||||
for (auto *loop : ioloops)
|
||||
{
|
||||
if (dbInfo._dbType == drogon::orm::ClientType::Sqlite3)
|
||||
{
|
||||
LOG_ERROR << "Sqlite3 don't support fast mode";
|
||||
abort();
|
||||
}
|
||||
if (dbInfo._dbType == drogon::orm::ClientType::PostgreSQL ||
|
||||
dbInfo._dbType == drogon::orm::ClientType::Mysql)
|
||||
{
|
||||
_dbFastClientsMap[dbInfo._name][loop] =
|
||||
std::shared_ptr<drogon::orm::DbClient>(
|
||||
new drogon::orm::DbClientLockFree(
|
||||
dbInfo._connectionInfo,
|
||||
loop,
|
||||
dbInfo._dbType,
|
||||
dbInfo._connectionNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dbInfo._dbType == drogon::orm::ClientType::PostgreSQL)
|
||||
{
|
||||
#if USE_POSTGRESQL
|
||||
_dbClientsMap[dbInfo._name] =
|
||||
drogon::orm::DbClient::newPgClient(
|
||||
dbInfo._connectionInfo, dbInfo._connectionNumber);
|
||||
#endif
|
||||
}
|
||||
else if (dbInfo._dbType == drogon::orm::ClientType::Mysql)
|
||||
{
|
||||
#if USE_MYSQL
|
||||
_dbClientsMap[dbInfo._name] =
|
||||
drogon::orm::DbClient::newMysqlClient(
|
||||
dbInfo._connectionInfo, dbInfo._connectionNumber);
|
||||
#endif
|
||||
}
|
||||
else if (dbInfo._dbType == drogon::orm::ClientType::Sqlite3)
|
||||
{
|
||||
#if USE_SQLITE3
|
||||
_dbClientsMap[dbInfo._name] =
|
||||
drogon::orm::DbClient::newSqlite3Client(
|
||||
dbInfo._connectionInfo, dbInfo._connectionNumber);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DbClientManager::createDbClient(const std::string &dbType,
|
||||
const std::string &host,
|
||||
const u_short port,
|
||||
const std::string &databaseName,
|
||||
const std::string &userName,
|
||||
const std::string &password,
|
||||
const size_t connectionNum,
|
||||
const std::string &filename,
|
||||
const std::string &name,
|
||||
const bool isFast)
|
||||
{
|
||||
auto connStr = utils::formattedString("host=%s port=%u dbname=%s user=%s",
|
||||
host.c_str(),
|
||||
port,
|
||||
databaseName.c_str(),
|
||||
userName.c_str());
|
||||
if (!password.empty())
|
||||
{
|
||||
connStr += " password=";
|
||||
connStr += password;
|
||||
}
|
||||
std::string type = dbType;
|
||||
std::transform(type.begin(), type.end(), type.begin(), tolower);
|
||||
DbInfo info;
|
||||
info._connectionInfo = connStr;
|
||||
info._connectionNumber = connectionNum;
|
||||
info._isFast = isFast;
|
||||
info._name = name;
|
||||
|
||||
if (type == "postgresql")
|
||||
{
|
||||
#if USE_POSTGRESQL
|
||||
info._dbType = orm::ClientType::PostgreSQL;
|
||||
_dbInfos.push_back(info);
|
||||
#else
|
||||
std::cout
|
||||
<< "The PostgreSQL is not supported by drogon, please install "
|
||||
"the development library first."
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
else if (type == "mysql")
|
||||
{
|
||||
#if USE_MYSQL
|
||||
info._dbType = orm::ClientType::Mysql;
|
||||
_dbInfos.push_back(info);
|
||||
#else
|
||||
std::cout << "The Mysql is not supported by drogon, please install the "
|
||||
"development library first."
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
else if (type == "sqlite3")
|
||||
{
|
||||
#if USE_SQLITE3
|
||||
std::string sqlite3ConnStr = "filename=" + filename;
|
||||
info._connectionInfo = sqlite3ConnStr;
|
||||
info._dbType = orm::ClientType::Sqlite3;
|
||||
_dbInfos.push_back(info);
|
||||
#else
|
||||
std::cout
|
||||
<< "The Sqlite3 is not supported by drogon, please install the "
|
||||
"development library first."
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
70
orm_lib/src/DbClientManager.h
Normal file
70
orm_lib/src/DbClientManager.h
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
*
|
||||
* DbClientManager.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/orm/DbClient.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <trantor/net/EventLoop.h>
|
||||
#include <string>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
namespace orm
|
||||
{
|
||||
class DbClientManager : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
void createDbClients(const std::vector<trantor::EventLoop *> &ioloops);
|
||||
DbClientPtr getDbClient(const std::string &name)
|
||||
{
|
||||
assert(_dbClientsMap.find(name) != _dbClientsMap.end());
|
||||
return _dbClientsMap[name];
|
||||
}
|
||||
|
||||
DbClientPtr getFastDbClient(const std::string &name)
|
||||
{
|
||||
assert(_dbFastClientsMap[name].find(
|
||||
trantor::EventLoop::getEventLoopOfCurrentThread()) !=
|
||||
_dbFastClientsMap[name].end());
|
||||
return _dbFastClientsMap
|
||||
[name][trantor::EventLoop::getEventLoopOfCurrentThread()];
|
||||
}
|
||||
void createDbClient(const std::string &dbType,
|
||||
const std::string &host,
|
||||
const u_short port,
|
||||
const std::string &databaseName,
|
||||
const std::string &userName,
|
||||
const std::string &password,
|
||||
const size_t connectionNum,
|
||||
const std::string &filename,
|
||||
const std::string &name,
|
||||
const bool isFast);
|
||||
|
||||
private:
|
||||
std::map<std::string, DbClientPtr> _dbClientsMap;
|
||||
struct DbInfo
|
||||
{
|
||||
std::string _name;
|
||||
std::string _connectionInfo;
|
||||
ClientType _dbType;
|
||||
bool _isFast;
|
||||
size_t _connectionNumber;
|
||||
};
|
||||
std::vector<DbInfo> _dbInfos;
|
||||
std::map<std::string, std::map<trantor::EventLoop *, orm::DbClientPtr>>
|
||||
_dbFastClientsMap;
|
||||
};
|
||||
} // namespace orm
|
||||
} // namespace drogon
|
||||
Loading…
x
Reference in New Issue
Block a user