drogon/examples/simple_example/main.cc

354 lines
12 KiB
C++

#include "CustomCtrl.h"
#include "CustomHeaderFilter.h"
#include "DigestAuthFilter.h"
#include <drogon/drogon.h>
#include <vector>
#include <string>
#include <iostream>
using namespace drogon;
using namespace std::chrono_literals;
class A : public DrObjectBase
{
public:
void handle(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
int p1,
const std::string &p2,
const std::string &p3,
int p4) const
{
HttpViewData data;
data.insert("title", std::string("ApiTest::get"));
std::unordered_map<std::string, std::string> para;
para["int p1"] = std::to_string(p1);
para["string p2"] = p2;
para["string p3"] = p3;
para["int p4"] = std::to_string(p4);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
static void staticHandle(
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
int p1,
const std::string &p2,
const std::string &p3,
int p4)
{
HttpViewData data;
data.insert("title", std::string("ApiTest::get"));
std::unordered_map<std::string, std::string> para;
para["int p1"] = std::to_string(p1);
para["string p2"] = p2;
para["string p3"] = p3;
para["int p4"] = std::to_string(p4);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
};
class B : public DrObjectBase
{
public:
void operator()(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
int p1,
int p2)
{
HttpViewData data;
data.insert("title", std::string("ApiTest::get"));
std::unordered_map<std::string, std::string> para;
para["p1"] = std::to_string(p1);
para["p2"] = std::to_string(p2);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
};
class C : public drogon::HttpController<C>
{
public:
METHOD_LIST_BEGIN
ADD_METHOD_TO(C::priv, "/priv/resource", Get, "DigestAuthFilter");
METHOD_LIST_END
void priv(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) const
{
auto resp = HttpResponse::newHttpResponse();
resp->setBody("<P>private content, only for authenticated users</P>");
callback(resp);
}
};
namespace api
{
namespace v1
{
class Test : public HttpController<Test>
{
public:
METHOD_LIST_BEGIN
METHOD_ADD(Test::get,
"get/{2}/{1}",
Get); // path is /api/v1/test/get/{arg2}/{arg1}
METHOD_ADD(Test::list,
"/{2}/info",
Get); // path is /api/v1/test/{arg2}/info
METHOD_LIST_END
void get(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
int p1,
int p2) const
{
HttpViewData data;
data.insert("title", std::string("ApiTest::get"));
std::unordered_map<std::string, std::string> para;
para["p1"] = std::to_string(p1);
para["p2"] = std::to_string(p2);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
void list(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
int p1,
int p2) const
{
HttpViewData data;
data.insert("title", std::string("ApiTest::get"));
std::unordered_map<std::string, std::string> para;
para["p1"] = std::to_string(p1);
para["p2"] = std::to_string(p2);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
};
} // namespace v1
} // namespace api
using namespace std::placeholders;
using namespace drogon;
namespace drogon
{
template <>
string_view fromRequest(const HttpRequest &req)
{
return req.body();
}
} // namespace drogon
/// Some examples in the main function show some common functions of drogon. In
/// practice, we don't need such a lengthy main function.
int main()
{
std::cout << banner << std::endl;
// app().addListener("::1", 8848); //ipv6
app().addListener("0.0.0.0", 8848);
// https
if (app().supportSSL())
{
drogon::app()
.setSSLFiles("server.pem", "server.pem")
.addListener("0.0.0.0", 8849, true);
}
// Class function example
app().registerHandler("/api/v1/handle1/{}/{}/?p3={}&p4={}", &A::handle);
app().registerHandler(
"/api/v1/handle11/{int p1}/{string p2}/?p3={string p3}&p4={int p4}",
&A::staticHandle);
// Lambda example
app().registerHandler(
"/api/v1/handle2/{int a}/{float b}",
[](const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
int a, // here the `a` parameter is converted from the number 1
// parameter in the path.
float b, // here the `b` parameter is converted from the number 2
// parameter in the path.
string_view &&body, // here the `body` parameter is converted from
// req->as<string_view>();
const std::shared_ptr<Json::Value>
&jsonPtr // here the `jsonPtr` parameter is converted from
// req->as<std::shared_ptr<Json::Value>>();
) {
HttpViewData data;
data.insert("title", std::string("ApiTest::get"));
std::unordered_map<std::string, std::string> para;
para["a"] = std::to_string(a);
para["b"] = std::to_string(b);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
LOG_DEBUG << body.data();
assert(!jsonPtr);
});
// Functor example
B b;
app().registerHandler("/api/v1/handle3/{1}/{2}", b);
// API example for std::function
A tmp;
std::function<void(const HttpRequestPtr &,
std::function<void(const HttpResponsePtr &)> &&,
int,
const std::string &,
const std::string &,
int)>
func = std::bind(&A::handle, &tmp, _1, _2, _3, _4, _5, _6);
app().registerHandler("/api/v1/handle4/{4:p4}/{3:p3}/{1:p1}", func);
app().setDocumentRoot("./");
app().enableSession(60);
std::map<std::string, std::string> config_credentials;
std::string realm("drogonRealm");
std::string opaque("drogonOpaque");
// Load configuration
app().loadConfigFile("config.example.json");
auto &json = app().getCustomConfig();
if (json.empty())
{
std::cout << "empty custom config!" << std::endl;
}
else
{
if (!json["realm"].empty())
{
realm = json["realm"].asString();
}
if (!json["opaque"].empty())
{
opaque = json["opaque"].asString();
}
for (auto &&i : json["credentials"])
{
config_credentials[i["user"].asString()] = i["password"].asString();
}
}
// Install Digest Authentication Filter using custom config credentials,
// used by C HttpController (/C/priv/resource)
auto auth_filter =
std::make_shared<DigestAuthFilter>(config_credentials, realm, opaque);
app().registerFilter(auth_filter);
// Install custom controller
auto ctrlPtr = std::make_shared<CustomCtrl>("Hi");
app().registerController(ctrlPtr);
// Install custom filter
auto filterPtr =
std::make_shared<CustomHeaderFilter>("custom_header", "yes");
app().registerFilter(filterPtr);
app().setIdleConnectionTimeout(30s);
// AOP example
app().registerBeginningAdvice(
[]() { LOG_DEBUG << "Event loop is running!"; });
app().registerNewConnectionAdvice([](const trantor::InetAddress &peer,
const trantor::InetAddress &local) {
LOG_DEBUG << "New connection: " << peer.toIpPort() << "-->"
<< local.toIpPort();
return true;
});
app().registerPreRoutingAdvice([](const drogon::HttpRequestPtr &req,
drogon::AdviceCallback &&acb,
drogon::AdviceChainCallback &&accb) {
LOG_DEBUG << "preRouting1";
accb();
});
app().registerPostRoutingAdvice([](const drogon::HttpRequestPtr &req,
drogon::AdviceCallback &&acb,
drogon::AdviceChainCallback &&accb) {
LOG_DEBUG << "postRouting1";
LOG_DEBUG << "Matched path=" << req->matchedPathPatternData();
for (auto &cookie : req->cookies())
{
LOG_DEBUG << "cookie: " << cookie.first << "=" << cookie.second;
}
accb();
});
app().registerPreHandlingAdvice([](const drogon::HttpRequestPtr &req,
drogon::AdviceCallback &&acb,
drogon::AdviceChainCallback &&accb) {
LOG_DEBUG << "preHandling1";
accb();
});
app().registerPostHandlingAdvice([](const drogon::HttpRequestPtr &,
const drogon::HttpResponsePtr &resp) {
LOG_DEBUG << "postHandling1";
resp->addHeader("Access-Control-Allow-Origin", "*");
});
app().registerPreRoutingAdvice([](const drogon::HttpRequestPtr &req) {
LOG_DEBUG << "preRouting observer";
});
app().registerPostRoutingAdvice([](const drogon::HttpRequestPtr &req) {
LOG_DEBUG << "postRouting observer";
});
app().registerPreHandlingAdvice([](const drogon::HttpRequestPtr &req) {
LOG_DEBUG << "preHanding observer";
});
app().registerSyncAdvice([](const HttpRequestPtr &req) -> HttpResponsePtr {
static const HttpResponsePtr nullResp;
if (req->path() == "/plaintext")
{
auto resp = HttpResponse::newHttpResponse();
resp->setBody("Hello, World!");
resp->setContentTypeCodeAndCustomString(
CT_TEXT_PLAIN, "Content-Type: text/plain\r\n");
return resp;
}
return nullResp;
});
// Output information of all handlers
auto handlerInfo = app().getHandlersInfo();
for (auto &info : handlerInfo)
{
std::cout << std::get<0>(info);
switch (std::get<1>(info))
{
case Get:
std::cout << " (GET) ";
break;
case Post:
std::cout << " (POST) ";
break;
case Delete:
std::cout << " (DELETE) ";
break;
case Put:
std::cout << " (PUT) ";
break;
case Options:
std::cout << " (OPTIONS) ";
break;
case Head:
std::cout << " (Head) ";
break;
case Patch:
std::cout << " (PATCH) ";
break;
default:
break;
}
std::cout << std::get<2>(info) << std::endl;
}
auto resp = HttpResponse::newFileResponse("index.html");
resp->setExpiredTime(0);
app().setCustom404Page(resp);
std::cout << "Date: "
<< std::string{drogon::utils::getHttpFullDate(
trantor::Date::now())}
<< std::endl;
app().run();
}