diff --git a/dDashboardServer/CMakeLists.txt b/dDashboardServer/CMakeLists.txt index efcb3eaa..05d1eb9d 100644 --- a/dDashboardServer/CMakeLists.txt +++ b/dDashboardServer/CMakeLists.txt @@ -1,17 +1,12 @@ set(DDASHBOARDSERVER_SOURCES "DashboardServer.cpp" - "MasterPacketHandler.cpp" - "routes/APIRoutes.cpp" - "routes/StaticRoutes.cpp" - "routes/DashboardRoutes.cpp" - "routes/WSRoutes.cpp" - "routes/AuthRoutes.cpp" - "auth/JWTUtils.cpp" - "auth/DashboardAuthService.cpp" - "auth/AuthMiddleware.cpp" - "auth/RequireAuthMiddleware.cpp" + "handlers/MasterPacketHandler.cpp" + "handlers/DashboardPacketHandler.cpp" ) +add_subdirectory(routes) +add_subdirectory(auth) + add_executable(DashboardServer ${DDASHBOARDSERVER_SOURCES}) target_include_directories(DashboardServer PRIVATE @@ -29,11 +24,12 @@ target_include_directories(DashboardServer PRIVATE "${PROJECT_SOURCE_DIR}/dServer" "${PROJECT_SOURCE_DIR}/thirdparty" "${PROJECT_SOURCE_DIR}/thirdparty/nlohmann" + "${PROJECT_SOURCE_DIR}/dDashboardServer" "${PROJECT_SOURCE_DIR}/dDashboardServer/auth" "${PROJECT_SOURCE_DIR}/dDashboardServer/routes" ) -target_link_libraries(DashboardServer ${COMMON_LIBRARIES} dWeb dServer bcrypt OpenSSL::Crypto) +target_link_libraries(DashboardServer ${COMMON_LIBRARIES} dWeb dServer bcrypt OpenSSL::Crypto DashboardRoutes DashboardAuth) # Copy static files and templates to build directory (always copy) diff --git a/dDashboardServer/DashboardServer.cpp b/dDashboardServer/DashboardServer.cpp index d8ff6ff0..ca4692fa 100644 --- a/dDashboardServer/DashboardServer.cpp +++ b/dDashboardServer/DashboardServer.cpp @@ -20,14 +20,16 @@ #include "Diagnostics.h" #include "Web.h" #include "Server.h" -#include "MasterPacketHandler.h" +#include "PacketHandler.h" +#include "handlers/MasterPacketHandler.h" +#include "handlers/DashboardPacketHandler.h" -#include "routes/ServerState.h" -#include "routes/APIRoutes.h" -#include "routes/StaticRoutes.h" -#include "routes/DashboardRoutes.h" -#include "routes/WSRoutes.h" -#include "routes/AuthRoutes.h" +#include "ServerState.h" +#include "APIRoutes.h" +#include "StaticRoutes.h" +#include "DashboardRoutes.h" +#include "WSRoutes.h" +#include "AuthRoutes.h" #include "AuthMiddleware.h" namespace Game { @@ -97,6 +99,9 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } + // Register dashboard-specific packet handlers + DashboardPacketHandler::RegisterDashboardHandlers(); + // Get master info from database std::string masterIP = "localhost"; uint32_t masterPort = 1000; @@ -160,10 +165,20 @@ int main(int argc, char** argv) { // Handle master server packets Packet* packet = g_Server->ReceiveFromMaster(); if (packet) { - MasterPacketHandler::HandleMasterPacket(packet); + RakNet::BitStream bitStream(packet->data, packet->length, false); + PacketHandler::HandlePacket(bitStream, packet->systemAddress); g_Server->DeallocateMasterPacket(packet); } + // Handle RakNet protocol packets from connected servers + packet = g_Server->Receive(); + while (packet) { + RakNet::BitStream bitStream(packet->data, packet->length, false); + PacketHandler::HandlePacket(bitStream, packet->systemAddress); + g_Server->DeallocatePacket(packet); + packet = g_Server->Receive(); + } + // Handle web requests Game::web.ReceiveRequests(); diff --git a/dDashboardServer/auth/CMakeLists.txt b/dDashboardServer/auth/CMakeLists.txt new file mode 100644 index 00000000..8f7a4aec --- /dev/null +++ b/dDashboardServer/auth/CMakeLists.txt @@ -0,0 +1,28 @@ +set(DASHBOARDAUTH_SOURCES + "JWTUtils.cpp" + "DashboardAuthService.cpp" + "AuthMiddleware.cpp" + "RequireAuthMiddleware.cpp" +) + +add_library(DashboardAuth STATIC ${DASHBOARDAUTH_SOURCES}) + +target_include_directories(DashboardAuth PRIVATE + "${PROJECT_SOURCE_DIR}/dCommon" + "${PROJECT_SOURCE_DIR}/dCommon/dClient" + "${PROJECT_SOURCE_DIR}/dCommon/dEnums" + "${PROJECT_SOURCE_DIR}/dDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/MySQL" + "${PROJECT_SOURCE_DIR}/dNet" + "${PROJECT_SOURCE_DIR}/dWeb" + "${PROJECT_SOURCE_DIR}/dServer" + "${PROJECT_SOURCE_DIR}/thirdparty" + "${PROJECT_SOURCE_DIR}/thirdparty/nlohmann" + "${PROJECT_SOURCE_DIR}/dDashboardServer/auth" +) + +target_link_libraries(DashboardAuth PRIVATE ${COMMON_LIBRARIES} dWeb dServer bcrypt OpenSSL::Crypto) diff --git a/dDashboardServer/handlers/DashboardPacketHandler.cpp b/dDashboardServer/handlers/DashboardPacketHandler.cpp new file mode 100644 index 00000000..b992f57d --- /dev/null +++ b/dDashboardServer/handlers/DashboardPacketHandler.cpp @@ -0,0 +1,68 @@ +#include "DashboardPacketHandler.h" + +#include "BitStreamUtils.h" +#include "Logger.h" +#include "Game.h" +#include "handlers/MasterPacketHandler.h" +#include +#include + +namespace DashboardPacketHandler { + std::map> g_ServiceHandlers; + + void DashboardNewIncomingConnection::Handle() { + LOG_DEBUG("DashboardPacketHandler: New incoming connection from %s", sysAddr.ToString(true)); + } + + void DashboardDisconnectionNotification::Handle() { + LOG_DEBUG("DashboardPacketHandler: Disconnection notification from %s", sysAddr.ToString(true)); + } + + void DashboardConnectionLost::Handle() { + LOG_DEBUG("DashboardPacketHandler: Connection lost with %s", sysAddr.ToString(true)); + } + + void DashboardConnectedPong::Handle() { + LOG_DEBUG("DashboardPacketHandler: Received pong from %s", sysAddr.ToString(true)); + } + + void DashboardUserPacketEnum::Handle() { + const auto it = g_ServiceHandlers.find(serviceType); + if (it != g_ServiceHandlers.end()) { + it->second(); + } else { + LOG_DEBUG("DashboardPacketHandler: No handler registered for service type %u from %s", static_cast(serviceType), sysAddr.ToString(true)); + } + } + + bool DashboardUserPacketEnum::Deserialize(RakNet::BitStream& bitStream) { + if (!PacketHandler::UserPacketEnum::Deserialize(bitStream)) { + return false; + } + VALIDATE_READ(bitStream.Read(serviceType)); + return true; + } + + void RegisterDashboardHandlers() { + // Override the default handlers with dashboard-specific implementations + PacketHandler::g_Handlers[ID_NEW_INCOMING_CONNECTION] = []() { + return std::make_unique(); + }; + PacketHandler::g_Handlers[ID_DISCONNECTION_NOTIFICATION] = []() { + return std::make_unique(); + }; + PacketHandler::g_Handlers[ID_CONNECTION_LOST] = []() { + return std::make_unique(); + }; + PacketHandler::g_Handlers[ID_CONNECTED_PONG] = []() { + return std::make_unique(); + }; + PacketHandler::g_Handlers[ID_USER_PACKET_ENUM] = []() { + return std::make_unique(); + }; + + // Register service type handlers + } +} + + diff --git a/dDashboardServer/handlers/DashboardPacketHandler.h b/dDashboardServer/handlers/DashboardPacketHandler.h new file mode 100644 index 00000000..c3eaf5be --- /dev/null +++ b/dDashboardServer/handlers/DashboardPacketHandler.h @@ -0,0 +1,37 @@ +#pragma once + +#include "PacketHandler.h" +#include "ServiceType.h" + +namespace DashboardPacketHandler { + // Dashboard-specific implementations of RakNet packet handlers + + struct DashboardNewIncomingConnection : public PacketHandler::NewIncomingConnection { + void Handle() override; + }; + + struct DashboardDisconnectionNotification : public PacketHandler::DisconnectionNotification { + void Handle() override; + }; + + struct DashboardConnectionLost : public PacketHandler::ConnectionLost { + void Handle() override; + }; + + struct DashboardConnectedPong : public PacketHandler::ConnectedPong { + void Handle() override; + }; + + struct DashboardUserPacketEnum : public PacketHandler::UserPacketEnum { + ServiceType serviceType{}; + + bool Deserialize(RakNet::BitStream& bitStream); + void Handle() override; + }; + + // Initialize dashboard-specific packet handlers + void RegisterDashboardHandlers(); +} + + + diff --git a/dDashboardServer/MasterPacketHandler.cpp b/dDashboardServer/handlers/MasterPacketHandler.cpp similarity index 65% rename from dDashboardServer/MasterPacketHandler.cpp rename to dDashboardServer/handlers/MasterPacketHandler.cpp index 85b2ed74..1ac72b13 100644 --- a/dDashboardServer/MasterPacketHandler.cpp +++ b/dDashboardServer/handlers/MasterPacketHandler.cpp @@ -5,30 +5,27 @@ #include "Game.h" #include "Logger.h" #include "RakNetTypes.h" -#include "routes/ServerState.h" +#include "ServerState.h" #include -#include namespace MasterPacketHandler { - namespace { - std::map()>> g_Handlers = { - {MessageType::Master::SERVER_INFO, []() { - return std::make_unique(); - }}, - {MessageType::Master::PLAYER_ADDED, []() { - return std::make_unique(); - }}, - {MessageType::Master::PLAYER_REMOVED, []() { - return std::make_unique(); - }}, - {MessageType::Master::SHUTDOWN_RESPONSE, []() { - return std::make_unique(); - }}, - {MessageType::Master::SHUTDOWN, []() { - return std::make_unique(); - }}, - }; - } + std::map()>> g_Handlers = { + {MessageType::Master::SERVER_INFO, []() { + return std::make_unique(); + }}, + {MessageType::Master::PLAYER_ADDED, []() { + return std::make_unique(); + }}, + {MessageType::Master::PLAYER_REMOVED, []() { + return std::make_unique(); + }}, + {MessageType::Master::SHUTDOWN_RESPONSE, []() { + return std::make_unique(); + }}, + {MessageType::Master::SHUTDOWN, []() { + return std::make_unique(); + }}, + }; bool ServerInfo::Deserialize(RakNet::BitStream& bitStream) { VALIDATE_READ(bitStream.Read(port)); @@ -42,8 +39,6 @@ namespace MasterPacketHandler { } void ServerInfo::Handle() { - std::lock_guard lock(ServerState::g_StatusMutex); - LOG("MasterPacketHandler: Processing SERVER_INFO for service type %i, zone %u, instance %u, port %u", serverType, zoneID, instanceID, port); switch (serverType) { @@ -94,7 +89,6 @@ namespace MasterPacketHandler { } void PlayerAdded::Handle() { - std::lock_guard lock(ServerState::g_StatusMutex); for (auto& world : ServerState::g_WorldInstances) { if (world.mapID == zoneID && world.instanceID == instanceID) { world.players++; @@ -111,7 +105,6 @@ namespace MasterPacketHandler { } void PlayerRemoved::Handle() { - std::lock_guard lock(ServerState::g_StatusMutex); for (auto& world : ServerState::g_WorldInstances) { if (world.mapID == zoneID && world.instanceID == instanceID) { if (world.players > 0) world.players--; @@ -129,8 +122,6 @@ namespace MasterPacketHandler { } void ShutdownResponse::Handle() { - std::lock_guard lock(ServerState::g_StatusMutex); - switch (serverType) { case ServiceType::AUTH: ServerState::g_AuthStatus.online = false; @@ -163,47 +154,4 @@ namespace MasterPacketHandler { LOG("Received SHUTDOWN command from Master"); Game::lastSignal = -1; // Trigger shutdown } - - void HandleMasterPacket(Packet* packet) { - if (!packet) return; - - switch (packet->data[0]) { - case ID_DISCONNECTION_NOTIFICATION: - case ID_CONNECTION_LOST: - LOG("Lost connection to Master Server"); - { - std::lock_guard lock(ServerState::g_StatusMutex); - ServerState::g_AuthStatus.online = false; - ServerState::g_ChatStatus.online = false; - ServerState::g_WorldInstances.clear(); - } - break; - case ID_CONNECTION_REQUEST_ACCEPTED: - LOG("Connected to Master Server"); - break; - case ID_USER_PACKET_ENUM: { - RakNet::BitStream inStream(packet->data, packet->length, false); - uint64_t header{}; - inStream.Read(header); - - const auto packetType = static_cast(header); - LOG_DEBUG("Received Master packet type: %i", packetType); - - auto it = g_Handlers.find(packetType); - if (it != g_Handlers.end()) { - auto handler = it->second(); - if (!handler->Deserialize(inStream)) { - LOG_DEBUG("Error deserializing Master packet type %i", packetType); - return; - } - handler->Handle(); - } else { - LOG_DEBUG("Unhandled Master packet type: %i", packetType); - } - break; - } - default: - break; - } - } } diff --git a/dDashboardServer/MasterPacketHandler.h b/dDashboardServer/handlers/MasterPacketHandler.h similarity index 91% rename from dDashboardServer/MasterPacketHandler.h rename to dDashboardServer/handlers/MasterPacketHandler.h index a2cd26d9..b4ebe6e8 100644 --- a/dDashboardServer/MasterPacketHandler.h +++ b/dDashboardServer/handlers/MasterPacketHandler.h @@ -1,4 +1,4 @@ -#pragma once + #pragma once #include #include @@ -74,6 +74,6 @@ namespace MasterPacketHandler { void Handle() override; }; - // Main handler function - void HandleMasterPacket(Packet* packet); + // Master packet handler registry + extern std::map()>> g_Handlers; } diff --git a/dDashboardServer/routes/APIRoutes.cpp b/dDashboardServer/routes/APIRoutes.cpp index 2e4345e5..1e4285fa 100644 --- a/dDashboardServer/routes/APIRoutes.cpp +++ b/dDashboardServer/routes/APIRoutes.cpp @@ -17,30 +17,7 @@ void RegisterAPIRoutes() { .method = eHTTPMethod::GET, .middleware = { std::make_shared(0) }, .handle = [](HTTPReply& reply, const HTTPContext& context) { - std::lock_guard lock(ServerState::g_StatusMutex); - - nlohmann::json response = { - {"auth", { - {"online", ServerState::g_AuthStatus.online}, - {"players", ServerState::g_AuthStatus.players}, - {"version", ServerState::g_AuthStatus.version} - }}, - {"chat", { - {"online", ServerState::g_ChatStatus.online}, - {"players", ServerState::g_ChatStatus.players} - }}, - {"worlds", nlohmann::json::array()} - }; - - for (const auto& world : ServerState::g_WorldInstances) { - response["worlds"].push_back({ - {"mapID", world.mapID}, - {"instanceID", world.instanceID}, - {"cloneID", world.cloneID}, - {"players", world.players}, - {"isPrivate", world.isPrivate} - }); - } + nlohmann::json response = ServerState::GetServerStateJson(); reply.status = eHTTPStatusCode::OK; reply.message = response.dump(); @@ -92,10 +69,18 @@ void RegisterAPIRoutes() { .method = eHTTPMethod::GET, .middleware = { std::make_shared(0) }, .handle = [](HTTPReply& reply, const HTTPContext& context) { - nlohmann::json response = {{"count", 0}, {"note", "Not yet implemented"}}; - reply.status = eHTTPStatusCode::OK; - reply.message = response.dump(); - reply.contentType = eContentType::APPLICATION_JSON; + try { + const uint32_t count = Database::Get()->GetCharacterCount(); + nlohmann::json response = {{"count", count}}; + reply.status = eHTTPStatusCode::OK; + reply.message = response.dump(); + reply.contentType = eContentType::APPLICATION_JSON; + } catch (std::exception& ex) { + LOG("Error in /api/characters/count: %s", ex.what()); + reply.status = eHTTPStatusCode::INTERNAL_SERVER_ERROR; + reply.message = "{\"error\":\"Database error\"}"; + reply.contentType = eContentType::APPLICATION_JSON; + } } }); } diff --git a/dDashboardServer/routes/CMakeLists.txt b/dDashboardServer/routes/CMakeLists.txt new file mode 100644 index 00000000..8d271175 --- /dev/null +++ b/dDashboardServer/routes/CMakeLists.txt @@ -0,0 +1,31 @@ +set(DASHBOARDROUTES_SOURCES + "APIRoutes.cpp" + "StaticRoutes.cpp" + "DashboardRoutes.cpp" + "WSRoutes.cpp" + "AuthRoutes.cpp" +) + +add_library(DashboardRoutes STATIC ${DASHBOARDROUTES_SOURCES}) + +target_include_directories(DashboardRoutes PRIVATE + "${PROJECT_SOURCE_DIR}/dCommon" + "${PROJECT_SOURCE_DIR}/dCommon/dClient" + "${PROJECT_SOURCE_DIR}/dCommon/dEnums" + "${PROJECT_SOURCE_DIR}/dDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/MySQL" + "${PROJECT_SOURCE_DIR}/dNet" + "${PROJECT_SOURCE_DIR}/dWeb" + "${PROJECT_SOURCE_DIR}/dServer" + "${PROJECT_SOURCE_DIR}/thirdparty" + "${PROJECT_SOURCE_DIR}/thirdparty/nlohmann" + "${PROJECT_SOURCE_DIR}/dDashboardServer/auth" + "${PROJECT_SOURCE_DIR}/dDashboardServer/routes" + "${PROJECT_SOURCE_DIR}/dDashboardServer/handlers" +) + +target_link_libraries(DashboardRoutes PRIVATE ${COMMON_LIBRARIES} dWeb dServer) diff --git a/dDashboardServer/routes/DashboardRoutes.cpp b/dDashboardServer/routes/DashboardRoutes.cpp index 720e5b7b..31a633c3 100644 --- a/dDashboardServer/routes/DashboardRoutes.cpp +++ b/dDashboardServer/routes/DashboardRoutes.cpp @@ -25,35 +25,16 @@ void RegisterDashboardRoutes() { env.set_lstrip_blocks(true); // Prepare data for template - nlohmann::json data; - // Get username from auth context - data["username"] = context.authenticatedUser; - data["gmLevel"] = context.gmLevel; + nlohmann::json data = context.GetUserDataJson(); - // Server status (placeholder data - will be updated with real data from master) - data["auth"]["online"] = ServerState::g_AuthStatus.online; - data["auth"]["players"] = ServerState::g_AuthStatus.players; - data["chat"]["online"] = ServerState::g_ChatStatus.online; - data["chat"]["players"] = ServerState::g_ChatStatus.players; - - // World instances - std::lock_guard lock(ServerState::g_StatusMutex); - data["worlds"] = nlohmann::json::array(); - for (const auto& world : ServerState::g_WorldInstances) { - data["worlds"].push_back({ - {"mapID", world.mapID}, - {"instanceID", world.instanceID}, - {"cloneID", world.cloneID}, - {"players", world.players}, - {"isPrivate", world.isPrivate} - }); - } + // Server status - merge with server state + nlohmann::json serverState = ServerState::GetServerStateJson(); + data.merge_patch(serverState); // Statistics - const uint32_t accountCount = Database::Get()->GetAccountCount(); data["stats"]["onlinePlayers"] = 0; // TODO: Get from server communication - data["stats"]["totalAccounts"] = accountCount; - data["stats"]["totalCharacters"] = 0; // TODO: Add GetCharacterCount to database interface + data["stats"]["totalAccounts"] = Database::Get()->GetAccountCount(); + data["stats"]["totalCharacters"] = Database::Get()->GetCharacterCount(); // Render template const std::string html = env.render_file("index.jinja2", data); @@ -82,9 +63,8 @@ void RegisterDashboardRoutes() { env.set_trim_blocks(true); env.set_lstrip_blocks(true); - // Render template with empty username - nlohmann::json data; - data["username"] = ""; + // Render template with empty user data (not authenticated) + nlohmann::json data = context.GetUserDataJson(); const std::string html = env.render_file("login.jinja2", data); reply.status = eHTTPStatusCode::OK; diff --git a/dDashboardServer/routes/DashboardRoutes.h b/dDashboardServer/routes/DashboardRoutes.h index 52064955..8eebbac2 100644 --- a/dDashboardServer/routes/DashboardRoutes.h +++ b/dDashboardServer/routes/DashboardRoutes.h @@ -1,3 +1,7 @@ #pragma once +#include "json.hpp" + +class HTTPContext; + void RegisterDashboardRoutes(); diff --git a/dDashboardServer/routes/ServerState.h b/dDashboardServer/routes/ServerState.h index 0b2592f8..1deead74 100644 --- a/dDashboardServer/routes/ServerState.h +++ b/dDashboardServer/routes/ServerState.h @@ -1,10 +1,10 @@ #pragma once #include -#include #include #include #include +#include "json.hpp" struct ServerStatus { bool online{false}; @@ -27,5 +27,26 @@ namespace ServerState { extern ServerStatus g_AuthStatus; extern ServerStatus g_ChatStatus; extern std::vector g_WorldInstances; - extern std::mutex g_StatusMutex; + + // Helper function to get all server state as JSON + inline nlohmann::json GetServerStateJson() { + nlohmann::json data; + data["auth"]["online"] = g_AuthStatus.online; + data["auth"]["players"] = g_AuthStatus.players; + data["chat"]["online"] = g_ChatStatus.online; + data["chat"]["players"] = g_ChatStatus.players; + + data["worlds"] = nlohmann::json::array(); + for (const auto& world : g_WorldInstances) { + data["worlds"].push_back({ + {"mapID", world.mapID}, + {"instanceID", world.instanceID}, + {"cloneID", world.cloneID}, + {"players", world.players}, + {"isPrivate", world.isPrivate} + }); + } + + return data; + } } diff --git a/dDashboardServer/routes/WSRoutes.cpp b/dDashboardServer/routes/WSRoutes.cpp index b20c40f2..673a5872 100644 --- a/dDashboardServer/routes/WSRoutes.cpp +++ b/dDashboardServer/routes/WSRoutes.cpp @@ -18,37 +18,14 @@ void RegisterWSRoutes() { } void BroadcastDashboardUpdate() { - std::lock_guard lock(ServerState::g_StatusMutex); - - nlohmann::json data = { - {"auth", { - {"online", ServerState::g_AuthStatus.online}, - {"players", ServerState::g_AuthStatus.players}, - {"version", ServerState::g_AuthStatus.version} - }}, - {"chat", { - {"online", ServerState::g_ChatStatus.online}, - {"players", ServerState::g_ChatStatus.players} - }}, - {"worlds", nlohmann::json::array()} - }; - - for (const auto& world : ServerState::g_WorldInstances) { - data["worlds"].push_back({ - {"mapID", world.mapID}, - {"instanceID", world.instanceID}, - {"cloneID", world.cloneID}, - {"players", world.players}, - {"isPrivate", world.isPrivate} - }); - } + // Get server state data (auth, chat, worlds) - mutex is acquired internally + nlohmann::json data = ServerState::GetServerStateJson(); // Add statistics try { - const uint32_t accountCount = Database::Get()->GetAccountCount(); data["stats"]["onlinePlayers"] = 0; // TODO: Get from server communication - data["stats"]["totalAccounts"] = accountCount; - data["stats"]["totalCharacters"] = 0; // TODO: Add GetCharacterCount to database interface + data["stats"]["totalAccounts"] = Database::Get()->GetAccountCount(); + data["stats"]["totalCharacters"] = Database::Get()->GetCharacterCount(); } catch (const std::exception& ex) { LOG_DEBUG("Error getting stats: %s", ex.what()); } diff --git a/dDashboardServer/templates/header.jinja2 b/dDashboardServer/templates/header.jinja2 index 4240ad99..ab62a9cc 100644 --- a/dDashboardServer/templates/header.jinja2 +++ b/dDashboardServer/templates/header.jinja2 @@ -20,9 +20,6 @@ - diff --git a/dDatabase/GameDatabase/ITables/ICharInfo.h b/dDatabase/GameDatabase/ITables/ICharInfo.h index d28017f3..a5a0d44d 100644 --- a/dDatabase/GameDatabase/ITables/ICharInfo.h +++ b/dDatabase/GameDatabase/ITables/ICharInfo.h @@ -33,6 +33,9 @@ public: // Get the character ids for the given account. virtual std::vector GetAccountCharacterIds(const LWOOBJID accountId) = 0; + // Get the total number of characters in the database. + virtual uint32_t GetCharacterCount() = 0; + // Insert a new character into the database. virtual void InsertNewCharacter(const ICharInfo::Info info) = 0; diff --git a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h index 26d362d1..eb82df69 100644 --- a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h +++ b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h @@ -126,6 +126,7 @@ public: void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional characterId) override; void DeleteUgcBuild(const LWOOBJID bigId) override; uint32_t GetAccountCount() override; + uint32_t GetCharacterCount() override; void RecordFailedAttempt(const uint32_t accountId) override; void ClearFailedAttempts(const uint32_t accountId) override; void SetLockout(const uint32_t accountId, const int64_t lockoutUntil) override; diff --git a/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp b/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp index 5d744b3d..49827bfc 100644 --- a/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp +++ b/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp @@ -54,6 +54,11 @@ std::vector MySQLDatabase::GetAccountCharacterIds(const LWOOBJID accou return toReturn; } +uint32_t MySQLDatabase::GetCharacterCount() { + auto res = ExecuteSelect("SELECT COUNT(*) as count FROM charinfo;"); + return res->next() ? res->getUInt("count") : 0; +} + void MySQLDatabase::InsertNewCharacter(const ICharInfo::Info info) { ExecuteInsert( "INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)", diff --git a/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h b/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h index a0b8bdfb..ba96456b 100644 --- a/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h +++ b/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h @@ -124,6 +124,7 @@ public: void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional characterId) override; void DeleteUgcBuild(const LWOOBJID bigId) override; uint32_t GetAccountCount() override; + uint32_t GetCharacterCount() override; void RecordFailedAttempt(const uint32_t accountId) override; void ClearFailedAttempts(const uint32_t accountId) override; void SetLockout(const uint32_t accountId, const int64_t lockoutUntil) override; diff --git a/dDatabase/GameDatabase/SQLite/Tables/CharInfo.cpp b/dDatabase/GameDatabase/SQLite/Tables/CharInfo.cpp index 6b3dab3b..c82771d8 100644 --- a/dDatabase/GameDatabase/SQLite/Tables/CharInfo.cpp +++ b/dDatabase/GameDatabase/SQLite/Tables/CharInfo.cpp @@ -55,6 +55,13 @@ std::vector SQLiteDatabase::GetAccountCharacterIds(const LWOOBJID acco return toReturn; } +uint32_t SQLiteDatabase::GetCharacterCount() { + auto [_, res] = ExecuteSelect("SELECT COUNT(*) as count FROM charinfo;"); + if (res.eof()) return 0; + + return res.getIntField("count"); +} + void SQLiteDatabase::InsertNewCharacter(const ICharInfo::Info info) { ExecuteInsert( "INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`, `prop_clone_id`) VALUES (?,?,?,?,?,?,(SELECT IFNULL(MAX(`prop_clone_id`), 0) + 1 FROM `charinfo`))", diff --git a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h index 948eb152..7d9e7908 100644 --- a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h +++ b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h @@ -103,6 +103,7 @@ class TestSQLDatabase : public GameDatabase { void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional characterId) override {}; void DeleteUgcBuild(const LWOOBJID bigId) override {}; uint32_t GetAccountCount() override { return 0; }; + uint32_t GetCharacterCount() override { return 0; }; void RecordFailedAttempt(const uint32_t accountId) override {}; void ClearFailedAttempts(const uint32_t accountId) override {}; void SetLockout(const uint32_t accountId, const int64_t lockoutUntil) override {}; diff --git a/dNet/CMakeLists.txt b/dNet/CMakeLists.txt index 9b780b84..f5854c36 100644 --- a/dNet/CMakeLists.txt +++ b/dNet/CMakeLists.txt @@ -6,6 +6,7 @@ set(DNET_SOURCES "AuthPackets.cpp" "MailInfo.cpp" "MasterPackets.cpp" "PacketUtils.cpp" + "PacketHandler.cpp" "WorldPackets.cpp" "ZoneInstanceManager.cpp") diff --git a/dNet/PacketHandler.cpp b/dNet/PacketHandler.cpp new file mode 100644 index 00000000..06860fef --- /dev/null +++ b/dNet/PacketHandler.cpp @@ -0,0 +1,130 @@ +#include "PacketHandler.h" + +#include "BitStream.h" +#include "DluAssert.h" +#include +#include +#include + +void RaknetPacket::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(static_cast(messageID)); +} + +bool RaknetPacket::Deserialize(RakNet::BitStream& bitStream) { + uint8_t id; + if (!bitStream.Read(id)) { + return false; + } + messageID = static_cast(id); + return true; +} + +namespace PacketHandler { + std::map()>> g_Handlers = { + {ID_INTERNAL_PING, []() { return std::make_unique(); }}, + {ID_PING, []() { return std::make_unique(); }}, + {ID_PING_OPEN_CONNECTIONS, []() { return std::make_unique(); }}, + {ID_CONNECTED_PONG, []() { return std::make_unique(); }}, + {ID_CONNECTION_REQUEST, []() { return std::make_unique(); }}, + {ID_SECURED_CONNECTION_RESPONSE, []() { return std::make_unique(); }}, + {ID_SECURED_CONNECTION_CONFIRMATION, []() { return std::make_unique(); }}, + {ID_RPC_MAPPING, []() { return std::make_unique(); }}, + {ID_DETECT_LOST_CONNECTIONS, []() { return std::make_unique(); }}, + {ID_OPEN_CONNECTION_REQUEST, []() { return std::make_unique(); }}, + {ID_OPEN_CONNECTION_REPLY, []() { return std::make_unique(); }}, + {ID_RPC, []() { return std::make_unique(); }}, + {ID_RPC_REPLY, []() { return std::make_unique(); }}, + {ID_OUT_OF_BAND_INTERNAL, []() { return std::make_unique(); }}, + {ID_CONNECTION_REQUEST_ACCEPTED, []() { return std::make_unique(); }}, + {ID_CONNECTION_ATTEMPT_FAILED, []() { return std::make_unique(); }}, + {ID_ALREADY_CONNECTED, []() { return std::make_unique(); }}, + {ID_NEW_INCOMING_CONNECTION, []() { return std::make_unique(); }}, + {ID_NO_FREE_INCOMING_CONNECTIONS, []() { return std::make_unique(); }}, + {ID_DISCONNECTION_NOTIFICATION, []() { return std::make_unique(); }}, + {ID_CONNECTION_LOST, []() { return std::make_unique(); }}, + {ID_RSA_PUBLIC_KEY_MISMATCH, []() { return std::make_unique(); }}, + {ID_CONNECTION_BANNED, []() { return std::make_unique(); }}, + {ID_INVALID_PASSWORD, []() { return std::make_unique(); }}, + {ID_MODIFIED_PACKET, []() { return std::make_unique(); }}, + {ID_TIMESTAMP, []() { return std::make_unique(); }}, + {ID_PONG, []() { return std::make_unique(); }}, + {ID_ADVERTISE_SYSTEM, []() { return std::make_unique(); }}, + {ID_REMOTE_DISCONNECTION_NOTIFICATION, []() { return std::make_unique(); }}, + {ID_REMOTE_CONNECTION_LOST, []() { return std::make_unique(); }}, + {ID_REMOTE_NEW_INCOMING_CONNECTION, []() { return std::make_unique(); }}, + {ID_DOWNLOAD_PROGRESS, []() { return std::make_unique(); }}, + {ID_FILE_LIST_TRANSFER_HEADER, []() { return std::make_unique(); }}, + {ID_FILE_LIST_TRANSFER_FILE, []() { return std::make_unique(); }}, + {ID_DDT_DOWNLOAD_REQUEST, []() { return std::make_unique(); }}, + {ID_TRANSPORT_STRING, []() { return std::make_unique(); }}, + {ID_REPLICA_MANAGER_CONSTRUCTION, []() { return std::make_unique(); }}, + {ID_REPLICA_MANAGER_DESTRUCTION, []() { return std::make_unique(); }}, + {ID_REPLICA_MANAGER_SCOPE_CHANGE, []() { return std::make_unique(); }}, + {ID_REPLICA_MANAGER_SERIALIZE, []() { return std::make_unique(); }}, + {ID_REPLICA_MANAGER_DOWNLOAD_STARTED, []() { return std::make_unique(); }}, + {ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE, []() { return std::make_unique(); }}, + {ID_CONNECTION_GRAPH_REQUEST, []() { return std::make_unique(); }}, + {ID_CONNECTION_GRAPH_REPLY, []() { return std::make_unique(); }}, + {ID_CONNECTION_GRAPH_UPDATE, []() { return std::make_unique(); }}, + {ID_CONNECTION_GRAPH_NEW_CONNECTION, []() { return std::make_unique(); }}, + {ID_CONNECTION_GRAPH_CONNECTION_LOST, []() { return std::make_unique(); }}, + {ID_CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION, []() { return std::make_unique(); }}, + {ID_ROUTE_AND_MULTICAST, []() { return std::make_unique(); }}, + {ID_RAKVOICE_OPEN_CHANNEL_REQUEST, []() { return std::make_unique(); }}, + {ID_RAKVOICE_OPEN_CHANNEL_REPLY, []() { return std::make_unique(); }}, + {ID_RAKVOICE_CLOSE_CHANNEL, []() { return std::make_unique(); }}, + {ID_RAKVOICE_DATA, []() { return std::make_unique(); }}, + {ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE, []() { return std::make_unique(); }}, + {ID_AUTOPATCHER_CREATION_LIST, []() { return std::make_unique(); }}, + {ID_AUTOPATCHER_DELETION_LIST, []() { return std::make_unique(); }}, + {ID_AUTOPATCHER_GET_PATCH, []() { return std::make_unique(); }}, + {ID_AUTOPATCHER_PATCH_LIST, []() { return std::make_unique(); }}, + {ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR, []() { return std::make_unique(); }}, + {ID_AUTOPATCHER_FINISHED_INTERNAL, []() { return std::make_unique(); }}, + {ID_AUTOPATCHER_FINISHED, []() { return std::make_unique(); }}, + {ID_AUTOPATCHER_RESTART_APPLICATION, []() { return std::make_unique(); }}, + {ID_NAT_PUNCHTHROUGH_REQUEST, []() { return std::make_unique(); }}, + {ID_NAT_TARGET_NOT_CONNECTED, []() { return std::make_unique(); }}, + {ID_NAT_TARGET_CONNECTION_LOST, []() { return std::make_unique(); }}, + {ID_NAT_CONNECT_AT_TIME, []() { return std::make_unique(); }}, + {ID_NAT_SEND_OFFLINE_MESSAGE_AT_TIME, []() { return std::make_unique(); }}, + {ID_NAT_IN_PROGRESS, []() { return std::make_unique(); }}, + {ID_DATABASE_QUERY_REQUEST, []() { return std::make_unique(); }}, + {ID_DATABASE_UPDATE_ROW, []() { return std::make_unique(); }}, + {ID_DATABASE_REMOVE_ROW, []() { return std::make_unique(); }}, + {ID_DATABASE_QUERY_REPLY, []() { return std::make_unique(); }}, + {ID_DATABASE_UNKNOWN_TABLE, []() { return std::make_unique(); }}, + {ID_DATABASE_INCORRECT_PASSWORD, []() { return std::make_unique(); }}, + {ID_READY_EVENT_SET, []() { return std::make_unique(); }}, + {ID_READY_EVENT_UNSET, []() { return std::make_unique(); }}, + {ID_READY_EVENT_ALL_SET, []() { return std::make_unique(); }}, + {ID_READY_EVENT_QUERY, []() { return std::make_unique(); }}, + {ID_LOBBY_GENERAL, []() { return std::make_unique(); }}, + {ID_AUTO_RPC_CALL, []() { return std::make_unique(); }}, + {ID_AUTO_RPC_REMOTE_INDEX, []() { return std::make_unique(); }}, + {ID_AUTO_RPC_UNKNOWN_REMOTE_INDEX, []() { return std::make_unique(); }}, + {ID_RPC_REMOTE_ERROR, []() { return std::make_unique(); }}, + {ID_USER_PACKET_ENUM, []() { return std::make_unique(); }}, + }; + + void HandlePacket(RakNet::BitStream& inStream, const SystemAddress& sysAddr) { + RaknetPacket data; + if (!data.Deserialize(inStream)) { + fprintf(stderr, "Error reading packet header\n"); + return; + } + + auto it = g_Handlers.find(data.messageID); + if (it != g_Handlers.end()) { + auto packet = it->second(); + packet->sysAddr = sysAddr; + if (!packet->Deserialize(inStream)) { + fprintf(stderr, "Error reading packet data for message ID: %i\n", data.messageID); + return; + } + packet->Handle(); + } else { + fprintf(stderr, "Unhandled packet with ID: %i\n", data.messageID); + } + } +} diff --git a/dNet/PacketHandler.h b/dNet/PacketHandler.h new file mode 100644 index 00000000..0b3469ad --- /dev/null +++ b/dNet/PacketHandler.h @@ -0,0 +1,456 @@ +#ifndef __RaknetPacket_H__ +#define __RaknetPacket_H__ + +#include +#include +#include +#include +#include "MessageIdentifiers.h" +#include + +struct Packet; +namespace RakNet { + class BitStream; +} + +struct RaknetPacket { + DefaultMessageIDTypes messageID = static_cast(-1); + SystemAddress sysAddr = UNASSIGNED_SYSTEM_ADDRESS; + + RaknetPacket() = default; + RaknetPacket(DefaultMessageIDTypes _messageID) : messageID{_messageID} {}; + + void Serialize(RakNet::BitStream& bitStream) const; + bool Deserialize(RakNet::BitStream& bitStream); + + virtual ~RaknetPacket() = default; + virtual void Handle() {}; +}; + +namespace PacketHandler { + struct InternalPing : public RaknetPacket { + void Handle() override {}; + InternalPing() : RaknetPacket(ID_INTERNAL_PING) {} + }; + + struct Ping : public RaknetPacket { + void Handle() override {}; + Ping() : RaknetPacket(ID_PING) {} + }; + + struct PingOpenConnections : public RaknetPacket { + void Handle() override {}; + PingOpenConnections() : RaknetPacket(ID_PING_OPEN_CONNECTIONS) {} + }; + + struct ConnectedPong : public RaknetPacket { + void Handle() override {}; + ConnectedPong() : RaknetPacket(ID_CONNECTED_PONG) {} + }; + + struct ConnectionRequest : public RaknetPacket { + void Handle() override {}; + ConnectionRequest() : RaknetPacket(ID_CONNECTION_REQUEST) {} + }; + + struct SecuredConnectionResponse : public RaknetPacket { + void Handle() override {}; + SecuredConnectionResponse() : RaknetPacket(ID_SECURED_CONNECTION_RESPONSE) {} + }; + + struct SecuredConnectionConfirmation : public RaknetPacket { + void Handle() override {}; + SecuredConnectionConfirmation() : RaknetPacket(ID_SECURED_CONNECTION_CONFIRMATION) {} + }; + + struct RPCMapping : public RaknetPacket { + void Handle() override {}; + RPCMapping() : RaknetPacket(ID_RPC_MAPPING) {} + }; + + struct DetectLostConnections : public RaknetPacket { + void Handle() override {}; + DetectLostConnections() : RaknetPacket(ID_DETECT_LOST_CONNECTIONS) {} + }; + + struct OpenConnectionRequest : public RaknetPacket { + void Handle() override {}; + OpenConnectionRequest() : RaknetPacket(ID_OPEN_CONNECTION_REQUEST) {} + }; + + struct OpenConnectionReply : public RaknetPacket { + void Handle() override {}; + OpenConnectionReply() : RaknetPacket(ID_OPEN_CONNECTION_REPLY) {} + }; + + struct RPC : public RaknetPacket { + void Handle() override {}; + RPC() : RaknetPacket(ID_RPC) {} + }; + + struct RPCReply : public RaknetPacket { + void Handle() override {}; + RPCReply() : RaknetPacket(ID_RPC_REPLY) {} + }; + + struct OutOfBandInternal : public RaknetPacket { + void Handle() override {}; + OutOfBandInternal() : RaknetPacket(ID_OUT_OF_BAND_INTERNAL) {} + }; + + struct ConnectionRequestAccepted : public RaknetPacket { + void Handle() override {}; + ConnectionRequestAccepted() : RaknetPacket(ID_CONNECTION_REQUEST_ACCEPTED) {} + }; + + struct ConnectionAttemptFailed : public RaknetPacket { + void Handle() override {}; + ConnectionAttemptFailed() : RaknetPacket(ID_CONNECTION_ATTEMPT_FAILED) {} + }; + + struct AlreadyConnected : public RaknetPacket { + void Handle() override {}; + AlreadyConnected() : RaknetPacket(ID_ALREADY_CONNECTED) {} + }; + + struct NewIncomingConnection : public RaknetPacket { + void Handle() override {}; + NewIncomingConnection() : RaknetPacket(ID_NEW_INCOMING_CONNECTION) {} + }; + + struct NoFreeIncomingConnections : public RaknetPacket { + void Handle() override {}; + NoFreeIncomingConnections() : RaknetPacket(ID_NO_FREE_INCOMING_CONNECTIONS) {} + }; + + struct DisconnectionNotification : public RaknetPacket { + void Handle() override {}; + DisconnectionNotification() : RaknetPacket(ID_DISCONNECTION_NOTIFICATION) {} + }; + + struct ConnectionLost : public RaknetPacket { + void Handle() override {}; + ConnectionLost() : RaknetPacket(ID_CONNECTION_LOST) {} + }; + + struct RSAPublicKeyMismatch : public RaknetPacket { + void Handle() override {}; + RSAPublicKeyMismatch() : RaknetPacket(ID_RSA_PUBLIC_KEY_MISMATCH) {} + }; + + struct ConnectionBanned : public RaknetPacket { + void Handle() override {}; + ConnectionBanned() : RaknetPacket(ID_CONNECTION_BANNED) {} + }; + + struct InvalidPassword : public RaknetPacket { + void Handle() override {}; + InvalidPassword() : RaknetPacket(ID_INVALID_PASSWORD) {} + }; + + struct ModifiedPacket : public RaknetPacket { + void Handle() override {}; + ModifiedPacket() : RaknetPacket(ID_MODIFIED_PACKET) {} + }; + + struct Timestamp : public RaknetPacket { + void Handle() override {}; + Timestamp() : RaknetPacket(ID_TIMESTAMP) {} + }; + + struct Pong : public RaknetPacket { + void Handle() override {}; + Pong() : RaknetPacket(ID_PONG) {} + }; + + struct AdvertiseSystem : public RaknetPacket { + void Handle() override {}; + AdvertiseSystem() : RaknetPacket(ID_ADVERTISE_SYSTEM) {} + }; + + struct RemoteDisconnectionNotification : public RaknetPacket { + void Handle() override {}; + RemoteDisconnectionNotification() : RaknetPacket(ID_REMOTE_DISCONNECTION_NOTIFICATION) {} + }; + + struct RemoteConnectionLost : public RaknetPacket { + void Handle() override {}; + RemoteConnectionLost() : RaknetPacket(ID_REMOTE_CONNECTION_LOST) {} + }; + + struct RemoteNewIncomingConnection : public RaknetPacket { + void Handle() override {}; + RemoteNewIncomingConnection() : RaknetPacket(ID_REMOTE_NEW_INCOMING_CONNECTION) {} + }; + + struct DownloadProgress : public RaknetPacket { + void Handle() override {}; + DownloadProgress() : RaknetPacket(ID_DOWNLOAD_PROGRESS) {} + }; + + struct FileListTransferHeader : public RaknetPacket { + void Handle() override {}; + FileListTransferHeader() : RaknetPacket(ID_FILE_LIST_TRANSFER_HEADER) {} + }; + + struct FileListTransferFile : public RaknetPacket { + void Handle() override {}; + FileListTransferFile() : RaknetPacket(ID_FILE_LIST_TRANSFER_FILE) {} + }; + + struct DDTDownloadRequest : public RaknetPacket { + void Handle() override {}; + DDTDownloadRequest() : RaknetPacket(ID_DDT_DOWNLOAD_REQUEST) {} + }; + + struct TransportString : public RaknetPacket { + void Handle() override {}; + TransportString() : RaknetPacket(ID_TRANSPORT_STRING) {} + }; + + struct ReplicaManagerConstruction : public RaknetPacket { + void Handle() override {}; + ReplicaManagerConstruction() : RaknetPacket(ID_REPLICA_MANAGER_CONSTRUCTION) {} + }; + + struct ReplicaManagerDestruction : public RaknetPacket { + void Handle() override {}; + ReplicaManagerDestruction() : RaknetPacket(ID_REPLICA_MANAGER_DESTRUCTION) {} + }; + + struct ReplicaManagerScopeChange : public RaknetPacket { + void Handle() override {}; + ReplicaManagerScopeChange() : RaknetPacket(ID_REPLICA_MANAGER_SCOPE_CHANGE) {} + }; + + struct ReplicaManagerSerialize : public RaknetPacket { + void Handle() override {}; + ReplicaManagerSerialize() : RaknetPacket(ID_REPLICA_MANAGER_SERIALIZE) {} + }; + + struct ReplicaManagerDownloadStarted : public RaknetPacket { + void Handle() override {}; + ReplicaManagerDownloadStarted() : RaknetPacket(ID_REPLICA_MANAGER_DOWNLOAD_STARTED) {} + }; + + struct ReplicaManagerDownloadComplete : public RaknetPacket { + void Handle() override {}; + ReplicaManagerDownloadComplete() : RaknetPacket(ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE) {} + }; + + struct ConnectionGraphRequest : public RaknetPacket { + void Handle() override {}; + ConnectionGraphRequest() : RaknetPacket(ID_CONNECTION_GRAPH_REQUEST) {} + }; + + struct ConnectionGraphReply : public RaknetPacket { + void Handle() override {}; + ConnectionGraphReply() : RaknetPacket(ID_CONNECTION_GRAPH_REPLY) {} + }; + + struct ConnectionGraphUpdate : public RaknetPacket { + void Handle() override {}; + ConnectionGraphUpdate() : RaknetPacket(ID_CONNECTION_GRAPH_UPDATE) {} + }; + + struct ConnectionGraphNewConnection : public RaknetPacket { + void Handle() override {}; + ConnectionGraphNewConnection() : RaknetPacket(ID_CONNECTION_GRAPH_NEW_CONNECTION) {} + }; + + struct ConnectionGraphConnectionLost : public RaknetPacket { + void Handle() override {}; + ConnectionGraphConnectionLost() : RaknetPacket(ID_CONNECTION_GRAPH_CONNECTION_LOST) {} + }; + + struct ConnectionGraphDisconnectionNotification : public RaknetPacket { + void Handle() override {}; + ConnectionGraphDisconnectionNotification() : RaknetPacket(ID_CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION) {} + }; + + struct RouteAndMulticast : public RaknetPacket { + void Handle() override {}; + RouteAndMulticast() : RaknetPacket(ID_ROUTE_AND_MULTICAST) {} + }; + + struct RakVoiceOpenChannelRequest : public RaknetPacket { + void Handle() override {}; + RakVoiceOpenChannelRequest() : RaknetPacket(ID_RAKVOICE_OPEN_CHANNEL_REQUEST) {} + }; + + struct RakVoiceOpenChannelReply : public RaknetPacket { + void Handle() override {}; + RakVoiceOpenChannelReply() : RaknetPacket(ID_RAKVOICE_OPEN_CHANNEL_REPLY) {} + }; + + struct RakVoiceCloseChannel : public RaknetPacket { + void Handle() override {}; + RakVoiceCloseChannel() : RaknetPacket(ID_RAKVOICE_CLOSE_CHANNEL) {} + }; + + struct RakVoiceData : public RaknetPacket { + void Handle() override {}; + RakVoiceData() : RaknetPacket(ID_RAKVOICE_DATA) {} + }; + + struct AutopatcherGetChangelistSinceDate : public RaknetPacket { + void Handle() override {}; + AutopatcherGetChangelistSinceDate() : RaknetPacket(ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE) {} + }; + + struct AutopatcherCreationList : public RaknetPacket { + void Handle() override {}; + AutopatcherCreationList() : RaknetPacket(ID_AUTOPATCHER_CREATION_LIST) {} + }; + + struct AutopatcherDeletionList : public RaknetPacket { + void Handle() override {}; + AutopatcherDeletionList() : RaknetPacket(ID_AUTOPATCHER_DELETION_LIST) {} + }; + + struct AutopatcherGetPatch : public RaknetPacket { + void Handle() override {}; + AutopatcherGetPatch() : RaknetPacket(ID_AUTOPATCHER_GET_PATCH) {} + }; + + struct AutopatcherPatchList : public RaknetPacket { + void Handle() override {}; + AutopatcherPatchList() : RaknetPacket(ID_AUTOPATCHER_PATCH_LIST) {} + }; + + struct AutopatcherRepositoryFatalError : public RaknetPacket { + void Handle() override {}; + AutopatcherRepositoryFatalError() : RaknetPacket(ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR) {} + }; + + struct AutopatcherFinishedInternal : public RaknetPacket { + void Handle() override {}; + AutopatcherFinishedInternal() : RaknetPacket(ID_AUTOPATCHER_FINISHED_INTERNAL) {} + }; + + struct AutopatcherFinished : public RaknetPacket { + void Handle() override {}; + AutopatcherFinished() : RaknetPacket(ID_AUTOPATCHER_FINISHED) {} + }; + + struct AutopatcherRestartApplication : public RaknetPacket { + void Handle() override {}; + AutopatcherRestartApplication() : RaknetPacket(ID_AUTOPATCHER_RESTART_APPLICATION) {} + }; + + struct NATpunchtroughRequest : public RaknetPacket { + void Handle() override {}; + NATpunchtroughRequest() : RaknetPacket(ID_NAT_PUNCHTHROUGH_REQUEST) {} + }; + + struct NATTargetNotConnected : public RaknetPacket { + void Handle() override {}; + NATTargetNotConnected() : RaknetPacket(ID_NAT_TARGET_NOT_CONNECTED) {} + }; + + struct NATTargetConnectionLost : public RaknetPacket { + void Handle() override {}; + NATTargetConnectionLost() : RaknetPacket(ID_NAT_TARGET_CONNECTION_LOST) {} + }; + + struct NATConnectAtTime : public RaknetPacket { + void Handle() override {}; + NATConnectAtTime() : RaknetPacket(ID_NAT_CONNECT_AT_TIME) {} + }; + + struct NATSendOfflineMessageAtTime : public RaknetPacket { + void Handle() override {}; + NATSendOfflineMessageAtTime() : RaknetPacket(ID_NAT_SEND_OFFLINE_MESSAGE_AT_TIME) {} + }; + + struct NATInProgress : public RaknetPacket { + void Handle() override {}; + NATInProgress() : RaknetPacket(ID_NAT_IN_PROGRESS) {} + }; + + struct DatabaseQueryRequest : public RaknetPacket { + void Handle() override {}; + DatabaseQueryRequest() : RaknetPacket(ID_DATABASE_QUERY_REQUEST) {} + }; + + struct DatabaseUpdateRow : public RaknetPacket { + void Handle() override {}; + DatabaseUpdateRow() : RaknetPacket(ID_DATABASE_UPDATE_ROW) {} + }; + + struct DatabaseRemoveRow : public RaknetPacket { + void Handle() override {}; + DatabaseRemoveRow() : RaknetPacket(ID_DATABASE_REMOVE_ROW) {} + }; + + struct DatabaseQueryReply : public RaknetPacket { + void Handle() override {}; + DatabaseQueryReply() : RaknetPacket(ID_DATABASE_QUERY_REPLY) {} + }; + + struct DatabaseUnknownTable : public RaknetPacket { + void Handle() override {}; + DatabaseUnknownTable() : RaknetPacket(ID_DATABASE_UNKNOWN_TABLE) {} + }; + + struct DatabaseIncorrectPassword : public RaknetPacket { + void Handle() override {}; + DatabaseIncorrectPassword() : RaknetPacket(ID_DATABASE_INCORRECT_PASSWORD) {} + }; + + struct ReadyEventSet : public RaknetPacket { + void Handle() override {}; + ReadyEventSet() : RaknetPacket(ID_READY_EVENT_SET) {} + }; + + struct ReadyEventUnset : public RaknetPacket { + void Handle() override {}; + ReadyEventUnset() : RaknetPacket(ID_READY_EVENT_UNSET) {} + }; + + struct ReadyEventAllSet : public RaknetPacket { + void Handle() override {}; + ReadyEventAllSet() : RaknetPacket(ID_READY_EVENT_ALL_SET) {} + }; + + struct ReadyEventQuery : public RaknetPacket { + void Handle() override {}; + ReadyEventQuery() : RaknetPacket(ID_READY_EVENT_QUERY) {} + }; + + struct LobbyGeneral : public RaknetPacket { + void Handle() override {}; + LobbyGeneral() : RaknetPacket(ID_LOBBY_GENERAL) {} + }; + + struct AutoRPCCall : public RaknetPacket { + void Handle() override {}; + AutoRPCCall() : RaknetPacket(ID_AUTO_RPC_CALL) {} + }; + + struct AutoRPCRemoteIndex : public RaknetPacket { + void Handle() override {}; + AutoRPCRemoteIndex() : RaknetPacket(ID_AUTO_RPC_REMOTE_INDEX) {} + }; + + struct AutoRPCUnknownRemoteIndex : public RaknetPacket { + void Handle() override {}; + AutoRPCUnknownRemoteIndex() : RaknetPacket(ID_AUTO_RPC_UNKNOWN_REMOTE_INDEX) {} + }; + + struct RPCRemoteError : public RaknetPacket { + void Handle() override {}; + RPCRemoteError() : RaknetPacket(ID_RPC_REMOTE_ERROR) {} + }; + + struct UserPacketEnum : public RaknetPacket { + void Handle() override {}; + UserPacketEnum() : RaknetPacket(ID_USER_PACKET_ENUM) {} + }; + + extern std::map()>> g_Handlers; + + void HandlePacket(RakNet::BitStream& inStream, const SystemAddress& sysAddr); +} + +#endif // __RaknetPacket_H__ diff --git a/dWeb/HTTPContext.h b/dWeb/HTTPContext.h index dfcd015c..4d3000e8 100644 --- a/dWeb/HTTPContext.h +++ b/dWeb/HTTPContext.h @@ -5,6 +5,7 @@ #include #include #include "eHTTPStatusCode.h" +#include "json.hpp" /** * HTTP Request Context @@ -56,4 +57,14 @@ struct HTTPContext { std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); headers[lowerName] = value; } + + /** + * Get user data as JSON for template rendering + */ + nlohmann::json GetUserDataJson() const { + nlohmann::json userData; + userData["username"] = authenticatedUser; + userData["gmLevel"] = gmLevel; + return userData; + } };