2022-05-28 13:39:33 +00:00
|
|
|
#include "crow.h"
|
|
|
|
#include "crow/middlewares/session.h"
|
|
|
|
|
2022-06-21 12:38:22 +00:00
|
|
|
crow::response redirect()
|
|
|
|
{
|
2022-05-28 13:39:33 +00:00
|
|
|
crow::response rsp;
|
|
|
|
rsp.redirect("/");
|
|
|
|
return rsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
// Choose a storage kind for:
|
2022-06-21 12:38:22 +00:00
|
|
|
// - InMemoryStore stores all entries in memory
|
2022-05-28 13:39:33 +00:00
|
|
|
// - FileStore stores all entries in json files
|
|
|
|
using Session = crow::SessionMiddleware<crow::InMemoryStore>;
|
|
|
|
|
|
|
|
// Writing your own store is easy
|
|
|
|
// Check out the existing ones for guidelines
|
|
|
|
|
|
|
|
// Make sure the CookieParser is registered before the Session
|
2022-06-21 12:38:22 +00:00
|
|
|
crow::App<crow::CookieParser, Session> app{Session{
|
|
|
|
// choose a secret key for sigining sessions ids
|
|
|
|
"MY_SECRET_KEY",
|
|
|
|
// customize cookies
|
|
|
|
crow::CookieParser::Cookie("session").max_age(/*one day*/ 24 * 60 * 60).path("/"),
|
|
|
|
// set session id length (small value only for demonstration purposes)
|
|
|
|
4,
|
|
|
|
// init the store
|
|
|
|
crow::InMemoryStore{}}};
|
2022-05-28 13:39:33 +00:00
|
|
|
|
|
|
|
// List all values
|
|
|
|
CROW_ROUTE(app, "/")
|
|
|
|
([&](const crow::request& req) {
|
|
|
|
// get session as middleware context
|
|
|
|
auto& session = app.get_context<Session>(req);
|
2022-06-23 07:59:44 +00:00
|
|
|
// the session acts as a multi-type map
|
|
|
|
// that can store string, integers, doubles and bools
|
|
|
|
// besides get/set/remove it also supports more advanced locking operations
|
2022-05-28 13:39:33 +00:00
|
|
|
|
2022-06-23 07:59:44 +00:00
|
|
|
// Atomically increase number of views
|
|
|
|
// This will not skip a view even on multithreaded applications
|
|
|
|
// with multiple concurrent requests from a client
|
2022-05-28 13:39:33 +00:00
|
|
|
// if "views" doesn't exist, it'll be default initialized
|
2022-06-21 12:38:22 +00:00
|
|
|
session.apply("views", [](int v) {
|
|
|
|
return v + 1;
|
|
|
|
});
|
2022-05-28 13:39:33 +00:00
|
|
|
|
|
|
|
// get all currently present keys
|
|
|
|
auto keys = session.keys();
|
|
|
|
|
|
|
|
std::string out;
|
2022-06-21 12:38:22 +00:00
|
|
|
for (const auto& key : keys)
|
2022-06-23 07:59:44 +00:00
|
|
|
// .string(key) converts a value of any type to a string
|
2022-06-21 12:38:22 +00:00
|
|
|
out += "<p> " + key + " = " + session.string(key) + "</p>";
|
2022-05-28 13:39:33 +00:00
|
|
|
return out;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Get a key
|
|
|
|
CROW_ROUTE(app, "/get")
|
|
|
|
([&](const crow::request& req) {
|
|
|
|
auto& session = app.get_context<Session>(req);
|
|
|
|
auto key = req.url_params.get("key");
|
|
|
|
|
2022-06-23 07:59:44 +00:00
|
|
|
// get a string
|
|
|
|
// return "_NOT_FOUND_" if value is not found or of another type
|
|
|
|
std::string string_v = session.get(key, "_NOT_FOUND_");
|
|
|
|
// alternatively one can use
|
|
|
|
// session.get<std::string>(key)
|
|
|
|
// where the fallback is an empty value ""
|
2022-05-28 14:59:33 +00:00
|
|
|
(void)string_v;
|
2022-05-28 13:39:33 +00:00
|
|
|
|
2022-06-23 07:59:44 +00:00
|
|
|
// get int
|
|
|
|
// because supporting multiple integer types in a type bound map would be cumbersome,
|
|
|
|
// all integral values (except uint64_t) are promoted to int64_t
|
|
|
|
// that is why get<int>, get<uint32_t>, get<int64_t> are all accessing the same type
|
|
|
|
int int_v = session.get(key, -1);
|
2022-05-28 14:59:33 +00:00
|
|
|
(void)int_v;
|
2022-05-28 13:39:33 +00:00
|
|
|
|
|
|
|
return session.string(key);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Set a key
|
2022-05-28 13:42:40 +00:00
|
|
|
// A session is stored as soon as it becomes non empty
|
2022-05-28 13:39:33 +00:00
|
|
|
CROW_ROUTE(app, "/set")
|
|
|
|
([&](const crow::request& req) {
|
|
|
|
auto& session = app.get_context<Session>(req);
|
|
|
|
|
|
|
|
auto key = req.url_params.get("key");
|
|
|
|
auto value = req.url_params.get("value");
|
|
|
|
|
|
|
|
session.set(key, value);
|
|
|
|
|
|
|
|
return redirect();
|
|
|
|
});
|
|
|
|
|
2022-06-23 07:59:44 +00:00
|
|
|
// Remove a key
|
|
|
|
CROW_ROUTE(app, "/remove")
|
2022-05-28 13:39:33 +00:00
|
|
|
([&](const crow::request& req) {
|
|
|
|
auto& session = app.get_context<Session>(req);
|
|
|
|
auto key = req.url_params.get("key");
|
2022-06-23 07:59:44 +00:00
|
|
|
session.remove(key);
|
2022-05-28 13:39:33 +00:00
|
|
|
|
|
|
|
return redirect();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Manually lock a session for synchronization in parallel requests
|
|
|
|
CROW_ROUTE(app, "/lock")
|
|
|
|
([&](const crow::request& req) {
|
|
|
|
auto& session = app.get_context<Session>(req);
|
|
|
|
|
|
|
|
std::lock_guard<std::recursive_mutex> l(session.mutex());
|
|
|
|
|
2022-06-21 12:38:22 +00:00
|
|
|
if (session.get("views", 0) % 2 == 0)
|
|
|
|
{
|
2022-05-28 13:39:33 +00:00
|
|
|
session.set("even", true);
|
2022-06-21 12:38:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-06-23 07:59:44 +00:00
|
|
|
session.remove("even");
|
2022-05-28 13:39:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return redirect();
|
|
|
|
});
|
|
|
|
|
2022-06-21 12:38:22 +00:00
|
|
|
// Manually hand out session ids
|
|
|
|
// This allows sharing sessions between devices or binding them to users, etc.
|
|
|
|
// Session ids are signed so they don't have to be random tokens
|
|
|
|
CROW_ROUTE(app, "/login")
|
|
|
|
([&](const crow::request& req) {
|
|
|
|
auto& session = app.get_context<Session>(req);
|
|
|
|
|
|
|
|
if (!session.exists())
|
|
|
|
{
|
|
|
|
session.preset_id("user_email@email.com");
|
|
|
|
}
|
2022-06-22 17:47:13 +00:00
|
|
|
|
|
|
|
return redirect();
|
2022-06-21 12:38:22 +00:00
|
|
|
});
|
|
|
|
|
2022-05-28 13:39:33 +00:00
|
|
|
app.port(18080)
|
2022-06-21 12:38:22 +00:00
|
|
|
//.multithreaded()
|
|
|
|
.run();
|
2022-05-28 13:39:33 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|