Skip to content

Commit fd986b4

Browse files
committed
WIP: basic server, no features
1 parent c723ce2 commit fd986b4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+7845
-56
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
110110
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
111111

112112
find_package(MariaDB)
113+
find_package(OpenSSL REQUIRED)
114+
113115

114116
# Create a /resServer directory
115117
make_directory(${CMAKE_BINARY_DIR}/resServer)
@@ -322,6 +324,7 @@ endif()
322324
add_subdirectory(dWorldServer)
323325
add_subdirectory(dAuthServer)
324326
add_subdirectory(dChatServer)
327+
add_subdirectory(dDashboardServer)
325328
add_subdirectory(dMasterServer) # Add MasterServer last so it can rely on the other binaries
326329

327330
target_precompile_headers(

dChatServer/ChatWeb.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,24 @@
1919
#include "eGameMasterLevel.h"
2020
#include "dChatFilter.h"
2121
#include "TeamContainer.h"
22+
#include "HTTPContext.h"
2223

2324
using json = nlohmann::json;
2425

25-
void HandleHTTPPlayersRequest(HTTPReply& reply, std::string body) {
26+
void HandleHTTPPlayersRequest(HTTPReply& reply, const HTTPContext& context) {
2627
const json data = Game::playerContainer;
2728
reply.status = data.empty() ? eHTTPStatusCode::NO_CONTENT : eHTTPStatusCode::OK;
2829
reply.message = data.empty() ? "{\"error\":\"No Players Online\"}" : data.dump();
2930
}
3031

31-
void HandleHTTPTeamsRequest(HTTPReply& reply, std::string body) {
32+
void HandleHTTPTeamsRequest(HTTPReply& reply, const HTTPContext& context) {
3233
const json data = TeamContainer::GetTeamContainer();
3334
reply.status = data.empty() ? eHTTPStatusCode::NO_CONTENT : eHTTPStatusCode::OK;
3435
reply.message = data.empty() ? "{\"error\":\"No Teams Online\"}" : data.dump();
3536
}
3637

37-
void HandleHTTPAnnounceRequest(HTTPReply& reply, std::string body) {
38-
auto data = GeneralUtils::TryParse<json>(body);
38+
void HandleHTTPAnnounceRequest(HTTPReply& reply, const HTTPContext& context) {
39+
auto data = GeneralUtils::TryParse<json>(context.body);
3940
if (!data) {
4041
reply.status = eHTTPStatusCode::BAD_REQUEST;
4142
reply.message = "{\"error\":\"Invalid JSON\"}";
@@ -96,18 +97,21 @@ namespace ChatWeb {
9697
Game::web.RegisterHTTPRoute({
9798
.path = v1_route + "players",
9899
.method = eHTTPMethod::GET,
100+
.middleware = {},
99101
.handle = HandleHTTPPlayersRequest
100102
});
101103

102104
Game::web.RegisterHTTPRoute({
103105
.path = v1_route + "teams",
104106
.method = eHTTPMethod::GET,
107+
.middleware = {},
105108
.handle = HandleHTTPTeamsRequest
106109
});
107110

108111
Game::web.RegisterHTTPRoute({
109112
.path = v1_route + "announce",
110113
.method = eHTTPMethod::POST,
114+
.middleware = {},
111115
.handle = HandleHTTPAnnounceRequest
112116
});
113117

dCommon/dEnums/MessageType/Master.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ namespace MessageType {
2727
AFFIRM_TRANSFER_REQUEST,
2828
AFFIRM_TRANSFER_RESPONSE,
2929

30-
NEW_SESSION_ALERT
30+
NEW_SESSION_ALERT,
31+
32+
REQUEST_SERVER_LIST
3133
};
3234
}

dCommon/dEnums/ServiceType.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ enum class ServiceType : uint16_t {
55
COMMON = 0,
66
AUTH,
77
CHAT,
8-
WORLD = 4,
8+
DASHBOARD,
9+
WORLD,
910
CLIENT,
1011
MASTER,
1112
UNKNOWN

dDashboardServer/CMakeLists.txt

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
set(DDASHBOARDSERVER_SOURCES
2+
"DashboardServer.cpp"
3+
"MasterPacketHandler.cpp"
4+
"routes/APIRoutes.cpp"
5+
"routes/StaticRoutes.cpp"
6+
"routes/DashboardRoutes.cpp"
7+
"routes/WSRoutes.cpp"
8+
"routes/AuthRoutes.cpp"
9+
"auth/JWTUtils.cpp"
10+
"auth/DashboardAuthService.cpp"
11+
"auth/AuthMiddleware.cpp"
12+
"auth/RequireAuthMiddleware.cpp"
13+
)
14+
15+
add_executable(DashboardServer ${DDASHBOARDSERVER_SOURCES})
16+
17+
target_include_directories(DashboardServer PRIVATE
18+
"${PROJECT_SOURCE_DIR}/dCommon"
19+
"${PROJECT_SOURCE_DIR}/dCommon/dClient"
20+
"${PROJECT_SOURCE_DIR}/dCommon/dEnums"
21+
"${PROJECT_SOURCE_DIR}/dDatabase"
22+
"${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase"
23+
"${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables"
24+
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase"
25+
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables"
26+
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/MySQL"
27+
"${PROJECT_SOURCE_DIR}/dNet"
28+
"${PROJECT_SOURCE_DIR}/dWeb"
29+
"${PROJECT_SOURCE_DIR}/dServer"
30+
"${PROJECT_SOURCE_DIR}/thirdparty"
31+
"${PROJECT_SOURCE_DIR}/thirdparty/nlohmann"
32+
"${PROJECT_SOURCE_DIR}/dDashboardServer/auth"
33+
"${PROJECT_SOURCE_DIR}/dDashboardServer/routes"
34+
)
35+
36+
target_link_libraries(DashboardServer ${COMMON_LIBRARIES} dWeb dServer bcrypt OpenSSL::Crypto)
37+
38+
39+
# Copy static files and templates to build directory (always copy)
40+
add_custom_command(TARGET DashboardServer POST_BUILD
41+
COMMAND ${CMAKE_COMMAND} -E remove_directory
42+
${CMAKE_BINARY_DIR}/dDashboardServer/static
43+
COMMENT "Removing old static files"
44+
)
45+
46+
add_custom_command(TARGET DashboardServer POST_BUILD
47+
COMMAND ${CMAKE_COMMAND} -E copy_directory
48+
${CMAKE_CURRENT_SOURCE_DIR}/static
49+
${CMAKE_BINARY_DIR}/dDashboardServer/static
50+
COMMENT "Copying DashboardServer static files"
51+
)
52+
53+
add_custom_command(TARGET DashboardServer POST_BUILD
54+
COMMAND ${CMAKE_COMMAND} -E remove_directory
55+
${CMAKE_BINARY_DIR}/dDashboardServer/templates
56+
COMMENT "Removing old templates"
57+
)
58+
59+
add_custom_command(TARGET DashboardServer POST_BUILD
60+
COMMAND ${CMAKE_COMMAND} -E copy_directory
61+
${CMAKE_CURRENT_SOURCE_DIR}/templates
62+
${CMAKE_BINARY_DIR}/dDashboardServer/templates
63+
COMMENT "Copying DashboardServer templates"
64+
)
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#include <chrono>
2+
#include <cstdlib>
3+
#include <iostream>
4+
#include <thread>
5+
#include <csignal>
6+
#include <memory>
7+
8+
#include "CDClientDatabase.h"
9+
#include "CDClientManager.h"
10+
#include "Database.h"
11+
#include "dConfig.h"
12+
#include "Logger.h"
13+
#include "dServer.h"
14+
#include "AssetManager.h"
15+
#include "BinaryPathFinder.h"
16+
#include "ServiceType.h"
17+
#include "MessageType/Master.h"
18+
#include "Game.h"
19+
#include "BitStreamUtils.h"
20+
#include "Diagnostics.h"
21+
#include "Web.h"
22+
#include "Server.h"
23+
#include "MasterPacketHandler.h"
24+
25+
#include "routes/ServerState.h"
26+
#include "routes/APIRoutes.h"
27+
#include "routes/StaticRoutes.h"
28+
#include "routes/DashboardRoutes.h"
29+
#include "routes/WSRoutes.h"
30+
#include "routes/AuthRoutes.h"
31+
#include "AuthMiddleware.h"
32+
33+
namespace Game {
34+
Logger* logger = nullptr;
35+
dServer* server = nullptr;
36+
dConfig* config = nullptr;
37+
Game::signal_t lastSignal = 0;
38+
std::mt19937 randomEngine;
39+
}
40+
41+
// Define global server state
42+
namespace ServerState {
43+
ServerStatus g_AuthStatus{};
44+
ServerStatus g_ChatStatus{};
45+
std::vector<WorldInstanceInfo> g_WorldInstances{};
46+
std::mutex g_StatusMutex{};
47+
}
48+
49+
namespace {
50+
dServer* g_Server = nullptr;
51+
bool g_RequestedServerList = false;
52+
}
53+
54+
int main(int argc, char** argv) {
55+
Diagnostics::SetProduceMemoryDump(true);
56+
std::signal(SIGINT, Game::OnSignal);
57+
std::signal(SIGTERM, Game::OnSignal);
58+
59+
uint32_t maxClients = 999;
60+
uint32_t ourPort = 2006;
61+
std::string ourIP = "127.0.0.1";
62+
63+
// Read config
64+
Game::config = new dConfig("dashboardconfig.ini");
65+
66+
// Setup logger
67+
Server::SetupLogger("DashboardServer");
68+
if (!Game::logger) return EXIT_FAILURE;
69+
Game::config->LogSettings();
70+
71+
LOG("Starting Dashboard Server");
72+
73+
// Load settings
74+
if (Game::config->GetValue("max_clients") != "")
75+
maxClients = std::stoi(Game::config->GetValue("max_clients"));
76+
77+
if (Game::config->GetValue("port") != "")
78+
ourPort = std::atoi(Game::config->GetValue("port").c_str());
79+
80+
if (Game::config->GetValue("listen_ip") != "")
81+
ourIP = Game::config->GetValue("listen_ip");
82+
83+
// Connect to CDClient database
84+
try {
85+
const std::string cdclientPath = BinaryPathFinder::GetBinaryDir() / "resServer/CDServer.sqlite";
86+
CDClientDatabase::Connect(cdclientPath);
87+
} catch (std::exception& ex) {
88+
LOG("Failed to connect to CDClient database: %s", ex.what());
89+
return EXIT_FAILURE;
90+
}
91+
92+
// Connect to MySQL database
93+
try {
94+
Database::Connect();
95+
} catch (std::exception& ex) {
96+
LOG("Failed to connect to MySQL database: %s", ex.what());
97+
return EXIT_FAILURE;
98+
}
99+
100+
// Get master info from database
101+
std::string masterIP = "localhost";
102+
uint32_t masterPort = 1000;
103+
std::string masterPassword;
104+
auto masterInfo = Database::Get()->GetMasterInfo();
105+
if (masterInfo) {
106+
masterIP = masterInfo->ip;
107+
masterPort = masterInfo->port;
108+
masterPassword = masterInfo->password;
109+
}
110+
111+
// Setup network server for communicating with Master
112+
g_Server = new dServer(
113+
masterIP,
114+
ourPort,
115+
0,
116+
maxClients,
117+
false,
118+
false,
119+
Game::logger,
120+
masterIP,
121+
masterPort,
122+
ServiceType::DASHBOARD, // Connect as dashboard to master
123+
Game::config,
124+
&Game::lastSignal,
125+
masterPassword
126+
);
127+
128+
// Initialize web server
129+
if (!Game::web.Startup(ourIP, ourPort)) {
130+
LOG("Failed to start web server on %s:%d", ourIP.c_str(), ourPort);
131+
return EXIT_FAILURE;
132+
}
133+
134+
// Register global middleware
135+
Game::web.AddGlobalMiddleware(std::make_shared<AuthMiddleware>());
136+
137+
// Register routes in order: API, Static, Auth, WebSocket, Dashboard (dashboard MUST be last)
138+
RegisterAPIRoutes();
139+
RegisterStaticRoutes();
140+
RegisterAuthRoutes();
141+
RegisterWSRoutes();
142+
RegisterDashboardRoutes(); // Must be last - catches all unmatched routes
143+
144+
LOG("Dashboard Server started successfully on %s:%d", ourIP.c_str(), ourPort);
145+
LOG("Connected to Master Server at %s:%d", masterIP.c_str(), masterPort);
146+
147+
// Main loop
148+
auto lastTime = std::chrono::high_resolution_clock::now();
149+
auto lastBroadcast = lastTime;
150+
auto currentTime = lastTime;
151+
constexpr float deltaTime = 1.0f / 60.0f; // 60 FPS
152+
constexpr float broadcastInterval = 2000.0f; // Broadcast every 2 seconds
153+
154+
while (!Game::ShouldShutdown()) {
155+
currentTime = std::chrono::high_resolution_clock::now();
156+
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastTime).count();
157+
const auto elapsedSinceBroadcast = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastBroadcast).count();
158+
159+
if (elapsed >= 1000.0f / 60.0f) {
160+
// Handle master server packets
161+
Packet* packet = g_Server->ReceiveFromMaster();
162+
if (packet) {
163+
MasterPacketHandler::HandleMasterPacket(packet);
164+
g_Server->DeallocateMasterPacket(packet);
165+
}
166+
167+
// Handle web requests
168+
Game::web.ReceiveRequests();
169+
170+
// Broadcast dashboard updates periodically
171+
if (elapsedSinceBroadcast >= broadcastInterval) {
172+
BroadcastDashboardUpdate();
173+
lastBroadcast = currentTime;
174+
}
175+
176+
lastTime = currentTime;
177+
}
178+
179+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
180+
}
181+
182+
// Cleanup
183+
Database::Destroy("DashboardServer");
184+
delete g_Server;
185+
g_Server = nullptr;
186+
delete Game::logger;
187+
Game::logger = nullptr;
188+
delete Game::config;
189+
Game::config = nullptr;
190+
191+
return EXIT_SUCCESS;
192+
}

0 commit comments

Comments
 (0)