This commit is contained in:
Aaron Kimbrell
2026-02-24 20:35:09 -06:00
parent f1847d1f20
commit 910b92ffc7
24 changed files with 883 additions and 180 deletions

View File

@@ -17,30 +17,7 @@ void RegisterAPIRoutes() {
.method = eHTTPMethod::GET,
.middleware = { std::make_shared<RequireAuthMiddleware>(0) },
.handle = [](HTTPReply& reply, const HTTPContext& context) {
std::lock_guard<std::mutex> 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<RequireAuthMiddleware>(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;
}
}
});
}

View File

@@ -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)

View File

@@ -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<std::mutex> 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;

View File

@@ -1,3 +1,7 @@
#pragma once
#include "json.hpp"
class HTTPContext;
void RegisterDashboardRoutes();

View File

@@ -1,10 +1,10 @@
#pragma once
#include <chrono>
#include <mutex>
#include <vector>
#include <string>
#include <cstdint>
#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<WorldInstanceInfo> 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;
}
}

View File

@@ -18,37 +18,14 @@ void RegisterWSRoutes() {
}
void BroadcastDashboardUpdate() {
std::lock_guard<std::mutex> 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());
}