Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: chat web api mvp #1550

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
1 change: 1 addition & 0 deletions dChatServer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(DCHATSERVER_SOURCES
"ChatWebApi.cpp"
"ChatIgnoreList.cpp"
"ChatPacketHandler.cpp"
"PlayerContainer.cpp"
Expand Down
10 changes: 9 additions & 1 deletion dChatServer/ChatServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "eWorldMessageType.h"
#include "ChatIgnoreList.h"
#include "StringifiedEnum.h"
#include "ChatWebApi.h"

#include "Game.h"
#include "Server.h"
Expand All @@ -36,7 +37,7 @@ namespace Game {
AssetManager* assetManager = nullptr;
Game::signal_t lastSignal = 0;
std::mt19937 randomEngine;
PlayerContainer playerContainer;
PlayerContainer playerContainer;
}

void HandlePacket(Packet* packet);
Expand Down Expand Up @@ -122,6 +123,9 @@ int main(int argc, char** argv) {
uint32_t framesSinceMasterDisconnect = 0;
uint32_t framesSinceLastSQLPing = 0;

// start the web api thread
std::thread webAPIThread(ChatWebApi::Listen, ourPort);

Game::logger->Flush(); // once immediately before main loop
while (!Game::ShouldShutdown()) {
//Check if we're still connected to master:
Expand Down Expand Up @@ -174,6 +178,10 @@ int main(int argc, char** argv) {
delete Game::server;
delete Game::logger;
delete Game::config;

// rejoin the web api thread
ChatWebApi::Stop();
webAPIThread.join();

return EXIT_SUCCESS;
}
Expand Down
93 changes: 93 additions & 0 deletions dChatServer/ChatWebApi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include <cstdint>
#include <nlohmann/json.hpp>

#include "ChatWebApi.h"
#include "dCommonVars.h"
#include "eConnectionType.h"
#include "eChatMessageType.h"
#include "httplib.h"
#include "dServer.h"
#include "PlayerContainer.h"
#include "dConfig.h"

using json = nlohmann::json;

namespace {
httplib::Server m_APIServer;
}

void ChatWebApi::Listen(const uint32_t port) {
if (Game::config->GetValue("enable_chat_web_api") != "1") {
LOG("Chat Web API is disabled");
return;
}
LOG("Chat Web API is enabled, starting web server...");

m_APIServer.Post("/announce", [](const httplib::Request& req, httplib::Response& res) {
const json data = json::parse(req.body);
if (!data.contains("title")) {
res.set_content("{\"error\":\"Missing paramater: title\"}", "application/json");
res.status = 400;
return;
}
std::string title = data["title"];
if (!data.contains("message")) {
res.set_content("{\"error\":\"Missing paramater: message\"}", "application/json");
res.status = 400;
return;
}
std::string message = data["message"];
// build and send the packet to all world servers
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GM_ANNOUNCE);
bitStream.Write<uint32_t>(title.size());
bitStream.Write(title);
bitStream.Write<uint32_t>(message.size());
bitStream.Write(message);
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
});

m_APIServer.Get("/players", [](const httplib::Request& req, httplib::Response& res) {
auto data = json::array();
for (auto& [playerID, playerData ]: Game::playerContainer.GetAllPlayers()){
if (!playerData) continue;
data.push_back(playerData.to_json());
}
res.set_content(data.dump(), "application/json");
if (data.empty()) res.status = 204;
});

m_APIServer.Get("/teams", [](const httplib::Request& req, httplib::Response& res) {
auto data = json::array();
for (auto& teamData: Game::playerContainer.GetAllTeams()){
if (!teamData) continue;
json toInsert;
toInsert["id"] = teamData->teamID;
toInsert["loot_flag"] = teamData->lootFlag;
toInsert["local"] = teamData->local;

auto leader = Game::playerContainer.GetPlayerData(teamData->leaderID);
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved
toInsert["leader"] = leader.to_json();

json members;
for (auto& member : teamData->memberIDs){
auto playerData = Game::playerContainer.GetPlayerData(member);
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved
if (!playerData) continue;
members.push_back(playerData.to_json());
}
toInsert["members"] = members;
data.push_back(toInsert);
}
res.set_content(data.dump(), "application/json");
if (data.empty()) res.status = 204;
});

m_APIServer.listen(Game::config->GetValue("chat_web_api_listen_address").c_str(), port);
};

void ChatWebApi::Stop(){
if (Game::config->GetValue("enable_chat_web_api") == "1") {
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved
LOG("Stopping Chat Web API server...");
m_APIServer.stop();
}
}
6 changes: 6 additions & 0 deletions dChatServer/ChatWebApi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "httplib.h"
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved

namespace ChatWebApi {
void Listen(const uint32_t port);
void Stop();
};
21 changes: 19 additions & 2 deletions dChatServer/PlayerContainer.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#include "PlayerContainer.h"
#include "dNetCommon.h"
#include <iostream>
#include <algorithm>

#include "PlayerContainer.h"
#include "dNetCommon.h"
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved
#include "Game.h"
#include "Logger.h"
#include "ChatPacketHandler.h"
Expand All @@ -13,6 +14,22 @@
#include "dConfig.h"
#include "eChatMessageType.h"


const json PlayerData::to_json() const {
json data;
data["id"] = this->playerID;
data["name"] = this->playerName;
data["gm_level"] = this->gmLevel;
data["muted"] = this->GetIsMuted();

json zoneID;
zoneID["map_id"] = std::to_string(this->zoneID.GetMapID());
zoneID["instance_id"] = std::to_string(this->zoneID.GetInstanceID());
zoneID["clone_id"] = std::to_string(this->zoneID.GetCloneID());
data["zone_id"] = zoneID;
return data;
}

void PlayerContainer::Initialize() {
m_MaxNumberOfBestFriends =
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends")).value_or(m_MaxNumberOfBestFriends);
Expand Down
6 changes: 6 additions & 0 deletions dChatServer/PlayerContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include "dServer.h"
#include <unordered_map>

#include <nlohmann/json.hpp>
using json = nlohmann::json;
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved

enum class eGameMasterLevel : uint8_t;

struct IgnoreData {
Expand Down Expand Up @@ -36,6 +39,8 @@ struct PlayerData {
return muteExpire == 1 || muteExpire > time(NULL);
}

const json to_json() const;

SystemAddress sysAddr{};
LWOZONEID zoneID{};
LWOOBJID playerID = LWOOBJID_EMPTY;
Expand Down Expand Up @@ -88,6 +93,7 @@ class PlayerContainer {
LWOOBJID GetId(const std::u16string& playerName);
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
const std::vector<TeamData*> GetAllTeams() { return mTeams;};
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved

private:
LWOOBJID m_TeamIDCounter = 0;
Expand Down
8 changes: 8 additions & 0 deletions resources/chatconfig.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,11 @@ max_number_of_best_friends=5
# Change the value below to what you would like this to be (50 is live accurate)
# going over 50 will be allowed in some secnarios, but proper handling will require client modding
max_number_of_friends=50

# Enable or disable the chat web API, disabled by default
# It will run on the same port the chat server is running on, defined in shardconfig.ini
enable_chat_web_api=0

# If that chat web api is enabled, it will only listen for connections on this ip address
# 127.0.0.1 is localhost
chat_web_api_listen_address=127.0.0.1
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved
Loading