add per request attribute store (#259)
This commit is contained in:
parent
93573c99bf
commit
1414704b44
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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> ¶meters()
|
||||
const = 0;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue