22#include <boost/beast/version.hpp>
23#include <boost/uuid/string_generator.hpp>
24#include <fmt/chrono.h>
43 std::string_view path = [&]
46 size_t queryIndex = path.find(
'?');
47 if (queryIndex != std::string_view::npos)
48 path = path.substr(0, queryIndex);
52 context.
handler = [&]() -> HttpMethodHandlerMap::mapped_type
const*
54 switch (context.
request.method())
56 case boost::beast::http::verb::get:
57 case boost::beast::http::verb::head:
60 return itr !=
_getHandlers.end() ? &itr->second :
nullptr;
75 context.
response.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
81 return context.
handler->
Func(std::move(session), context);
86 context.
response.result(boost::beast::http::status::bad_request);
92 context.
response.result(boost::beast::http::status::unauthorized);
98 context.
response.result(boost::beast::http::status::not_found);
110 case boost::beast::http::verb::get:
116 std::string_view methodString =
ToStdStringView(boost::beast::http::to_string(method));
122 handlerMap[std::string(path)] = { .Func = std::move(handler), .Flags =
flags };
128 state->RemoteAddress = address;
134 while (state->Id.is_nil() ||
_sessions.contains(state->Id))
135 std::copy_n(Trinity::Crypto::GetRandomBytes<16>().begin(), 16, state->Id.begin());
137 TC_LOG_DEBUG(
_logger,
"Client at {} created new session {}", address.to_string(), boost::uuids::to_string(state->Id));
170 std::shared_ptr<SessionState> state;
174 auto itr =
_sessions.find(boost::uuids::string_generator()(
id.begin(),
id.end()));
177 TC_LOG_DEBUG(
_logger,
"Client at {} attempted to use a session {} that was expired", address.to_string(),
id);
184 if (state->RemoteAddress != address)
186 TC_LOG_ERROR(
_logger,
"Client at {} attempted to use a session {} that was last accessed from {}, denied access",
187 address.to_string(),
id, state->RemoteAddress.to_string());
201 bool wasActive =
true;
213 itr->second->InactiveTimestamp = TimePoint::clock::now() +
Minutes(5);
221 std::set<boost::uuids::uuid> inactiveSessions;
230 std::size_t inactiveSessionsCount = inactiveSessions.size();
233 for (
auto itr = inactiveSessions.begin(); itr != inactiveSessions.end(); )
236 if (sessionItr ==
_sessions.end() || sessionItr->second->InactiveTimestamp < now)
239 itr = inactiveSessions.erase(itr);
245 TC_LOG_DEBUG(
_logger,
"Killed {} inactive sessions", inactiveSessionsCount - inactiveSessions.size());
251 for (
auto itr = inactiveSessions.begin(); itr != inactiveSessions.end(); )
253 auto node = inactiveSessions.extract(itr++);
#define STRING_VIEW_FMT_ARG(str)
std::chrono::system_clock::time_point SystemTimePoint
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
std::chrono::minutes Minutes
Minutes shorthand typedef.
#define TC_LOG_DEBUG(filterType__, message__,...)
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_LOG_INFO(filterType__, message__,...)
#define TC_LOG_TRACE(filterType__, message__,...)
constexpr bool HasFlag(T flag) const
RequestHandlerResult HandleRequest(std::shared_ptr< AbstractSocket > session, RequestContext &context)
static RequestHandlerResult HandlePathNotFound(std::shared_ptr< AbstractSocket > session, RequestContext &context)
static RequestHandlerResult HandleUnauthorized(std::shared_ptr< AbstractSocket > session, RequestContext &context)
HttpMethodHandlerMap _getHandlers
HttpMethodHandlerMap _postHandlers
static RequestHandlerResult HandleBadRequest(std::shared_ptr< AbstractSocket > session, RequestContext &context)
void RegisterHandler(boost::beast::http::verb method, std::string_view path, std::function< RequestHandlerResult(std::shared_ptr< AbstractSocket > session, RequestContext &context)> handler, RequestHandlerFlag flags=RequestHandlerFlag::None)
std::map< std::string, RequestHandler, std::less<> > HttpMethodHandlerMap
std::map< boost::uuids::uuid, std::shared_ptr< SessionState > > _sessions
std::unique_ptr< Asio::DeadlineTimer > _inactiveSessionsKillTimer
std::set< boost::uuids::uuid > _inactiveSessions
void KillInactiveSessions()
std::shared_ptr< SessionState > FindAndRefreshSessionState(std::string_view id, boost::asio::ip::address const &address)
std::shared_mutex _sessionsMutex
void Start(Asio::IoContext &ioContext)
void InitAndStoreSessionState(std::shared_ptr< SessionState > state, boost::asio::ip::address const &address)
void MarkSessionInactive(boost::uuids::uuid const &id)
std::mutex _inactiveSessionsMutex
decltype(auto) post(boost::asio::io_context &ioContext, T &&t)
@ DoNotLogResponseContent
std::string_view ToStdStringView(boost::beast::string_view bsw)
TC_SHARED_API bool CanLogResponseContent(RequestContext const &context)
TC_SHARED_API bool CanLogRequestContent(RequestContext const &context)
Minutes GetSystemZoneOffsetAt(SystemTimePoint date)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
struct RequestHandler const * handler
std::function< RequestHandlerResult(std::shared_ptr< AbstractSocket > session, RequestContext &context)> Func
EnumFlag< RequestHandlerFlag > Flags