add per request attribute store (#259)

This commit is contained in:
Armstrong 2019-09-28 21:48:06 +08:00 committed by An Tao
parent 93573c99bf
commit 1414704b44
7 changed files with 217 additions and 0 deletions

View File

@ -355,6 +355,7 @@ install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT lib)
set(DROGON_HEADERS
lib/inc/drogon/Attribute.h
lib/inc/drogon/CacheMap.h
lib/inc/drogon/Cookie.h
lib/inc/drogon/DrClassMap.h

View File

@ -412,3 +412,35 @@ void ApiTest::formTest(const HttpRequestPtr &req,
auto resp = HttpResponse::newHttpJsonResponse(ret);
callback(resp);
}
void ApiTest::attributesTest(
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback)
{
AttributesPtr attributes = req->getAttributes();
const std::string key = "ATTR_ADDR";
Json::Value ret;
uint64_t data = (uint64_t)req.get();
if (attributes->find(key))
{
ret["result"] = "bad";
callback(HttpResponse::newHttpJsonResponse(ret));
return;
}
attributes->insert(key, data);
if (!attributes->find(key) || attributes->get<uint64_t>(key) != data)
{
ret["result"] = "bad";
}
else
{
ret["result"] = "ok";
}
callback(HttpResponse::newHttpJsonResponse(ret));
return;
}

View File

@ -33,6 +33,7 @@ class ApiTest : public drogon::HttpController<ApiTest>
Get); // path is /absolute/{arg1}
METHOD_ADD(ApiTest::jsonTest, "/json", Post);
METHOD_ADD(ApiTest::formTest, "/form", Post);
METHOD_ADD(ApiTest::attributesTest, "/attrs", Get);
METHOD_LIST_END
void get(const HttpRequestPtr &req,
@ -57,6 +58,9 @@ class ApiTest : public drogon::HttpController<ApiTest>
std::function<void(const HttpResponsePtr &)> &&callback);
void formTest(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
void attributesTest(
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
public:
ApiTest()

View File

@ -925,6 +925,33 @@ void doTest(const HttpClientPtr &client,
}
});
/// Test attributes
req = HttpRequest::newHttpRequest();
req->setMethod(drogon::Get);
req->setPath("/api/v1/apitest/attrs");
client->sendRequest(req,
[=](ReqResult result, const HttpResponsePtr &resp) {
if (result == ReqResult::Ok)
{
auto ret = resp->getJsonObject();
if (ret && (*ret)["result"].asString() == "ok")
{
outputGood(req, isHttps);
}
else
{
LOG_DEBUG << resp->getBody();
LOG_ERROR << "Error!";
exit(1);
}
}
else
{
LOG_ERROR << "Error!";
exit(1);
}
});
/// Test attachment download
req = HttpRequest::newHttpRequest();
req->setMethod(drogon::Get);

132
lib/inc/drogon/Attribute.h Normal file
View File

@ -0,0 +1,132 @@
/**
*
* Attribute.h
* armstrong@sweelia.com
*
* 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/utils/any.h>
#include <trantor/utils/Logger.h>
#include <map>
#include <memory>
namespace drogon
{
/**
* @brief This class represents a attribute stored in the request context.
* One can get or set any type of data to a attribute object.
*/
class Attributes
{
public:
/**
* @brief Get the data identified by the key parameter.
* @note if the data is not found, a default value is returned.
* For example:
* @code
auto &userName = attributesPtr->get<std::string>("user name");
@endcode
*/
template <typename T>
const T &get(const std::string &key) const
{
const static T nullVal = T();
auto it = _attributesMap.find(key);
if (it != _attributesMap.end())
{
if (typeid(T) == it->second.type())
{
return *(any_cast<T>(&(it->second)));
}
else
{
LOG_ERROR << "Bad type";
}
}
return nullVal;
}
/**
* @brief Get the 'any' object identified by the given key
*/
any &operator[](const std::string &key)
{
return _attributesMap[key];
}
/**
* @brief Insert a key-value pair
* @note here the any object can be created implicitly. for example
* @code
attributesPtr->insert("user name", userNameString);
@endcode
*/
void insert(const std::string &key, const any &obj)
{
_attributesMap[key] = obj;
}
/**
* @brief Insert a key-value pair
* @note here the any object can be created implicitly. for example
* @code
attributesPtr->insert("user name", userNameString);
@endcode
*/
void insert(const std::string &key, any &&obj)
{
_attributesMap[key] = std::move(obj);
}
/**
* @brief Erase the data identified by the given key.
*/
void erase(const std::string &key)
{
_attributesMap.erase(key);
}
/**
* @brief Retrun true if the data identified by the key exists.
*/
bool find(const std::string &key)
{
if (_attributesMap.find(key) == _attributesMap.end())
{
return false;
}
return true;
}
/**
* @brief Clear all attributes.
*/
void clear()
{
_attributesMap.clear();
}
/**
* @brief Constructor, usually called by the framework
*/
Attributes()
{
}
private:
typedef std::map<std::string, any> AttributesMap;
AttributesMap _attributesMap;
};
typedef std::shared_ptr<Attributes> AttributesPtr;
} // namespace drogon

View File

@ -17,6 +17,7 @@
#include <drogon/utils/string_view.h>
#include <drogon/HttpTypes.h>
#include <drogon/Session.h>
#include <drogon/Attribute.h>
#include <drogon/UploadFile.h>
#include <json/json.h>
#include <trantor/net/InetAddress.h>
@ -167,6 +168,15 @@ class HttpRequest
return session();
}
/// Get the attributes store to which the request belongs.
virtual AttributesPtr attributes() const = 0;
/// Get the attributes store to which the request belongs.
AttributesPtr getAttributes() const
{
return attributes();
}
/// Get parameters of the request.
virtual const std::unordered_map<std::string, std::string> &parameters()
const = 0;

View File

@ -60,6 +60,7 @@ class HttpRequestImpl : public HttpRequest
_parameters.clear();
_jsonPtr.reset();
_sessionPtr.reset();
_attributesPtr.reset();
_cacheFilePtr.reset();
_expect.clear();
_content.clear();
@ -340,6 +341,15 @@ class HttpRequestImpl : public HttpRequest
_sessionPtr = session;
}
virtual AttributesPtr attributes() const override
{
if (!_attributesPtr)
{
_attributesPtr = std::make_shared<Attributes>();
}
return _attributesPtr;
}
virtual const std::shared_ptr<Json::Value> jsonObject() const override
{
parseParametersOnce();
@ -422,6 +432,7 @@ class HttpRequestImpl : public HttpRequest
mutable std::unordered_map<std::string, std::string> _parameters;
mutable std::shared_ptr<Json::Value> _jsonPtr;
SessionPtr _sessionPtr;
mutable AttributesPtr _attributesPtr;
trantor::InetAddress _peer;
trantor::InetAddress _local;
trantor::Date _date;