Changeset View
Standalone View
source/lobby/XmppClient.cpp
Show All 32 Lines | |||||
#include "ps/ConfigDB.h" | #include "ps/ConfigDB.h" | ||||
#include "ps/Pyrogenesis.h" | #include "ps/Pyrogenesis.h" | ||||
#include "scriptinterface/ScriptExtraHeaders.h" // StructuredClone | #include "scriptinterface/ScriptExtraHeaders.h" // StructuredClone | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include <gloox/gloox.h> | #include <gloox/gloox.h> | ||||
//debug | //debug | ||||
#if 1 | #if 1 | ||||
Silier: revert | |||||
#define DbgXMPP(x) | #define DbgXMPP(x) | ||||
#else | #else | ||||
#define DbgXMPP(x) std::cout << x << std::endl; | #define DbgXMPP(x) std::cout << x << std::endl; | ||||
static std::string tag_xml(const glooxwrapper::IQ& iq) | static std::string tag_xml(const glooxwrapper::IQ& iq) | ||||
{ | { | ||||
std::string ret; | std::string ret; | ||||
glooxwrapper::Tag* tag = iq.tag(); | glooxwrapper::Tag* tag = iq.tag(); | ||||
Show All 38 Lines | : m_ScriptInterface(scriptInterface), | ||||
m_password(sPassword), | m_password(sPassword), | ||||
m_room(sRoom), | m_room(sRoom), | ||||
m_nick(sNick), | m_nick(sNick), | ||||
m_initialLoadComplete(false), | m_initialLoadComplete(false), | ||||
m_isConnected(false), | m_isConnected(false), | ||||
m_sessionManager(nullptr), | m_sessionManager(nullptr), | ||||
m_certStatus(gloox::CertStatus::CertOk), | m_certStatus(gloox::CertStatus::CertOk), | ||||
m_PlayerMapUpdate(false) | m_PlayerMapUpdate(false) | ||||
{ | { | ||||
if (m_ScriptInterface) | if (m_ScriptInterface) | ||||
Done Inline ActionsNo need to pass empty string to std::string, it has a valid default c-tor. vladislavbelov: No need to pass empty string to `std::string`, it has a valid default c-tor. | |||||
Not Done Inline ActionsInvalid naming should be m_PascalCase Stan: Invalid naming should be m_PascalCase | |||||
Done Inline Actionsyes, but cc says follow style of the document trying to edit as the rule above cc guidelines Silier: yes, but cc says follow style of the document trying to edit as the rule above cc guidelines | |||||
Not Done Inline ActionsThen m_PlayerMapUpdate is wrong. Stan: Then m_PlayerMapUpdate is wrong. | |||||
JS_AddExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), XmppClient::Trace, this); | JS_AddExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), XmppClient::Trace, this); | ||||
// Read lobby configuration from default.cfg | // Read lobby configuration from default.cfg | ||||
std::string sXpartamupp; | std::string sXpartamupp; | ||||
std::string sEchelon; | std::string sEchelon; | ||||
CFG_GET_VAL("lobby.server", m_server); | CFG_GET_VAL("lobby.server", m_server); | ||||
CFG_GET_VAL("lobby.xpartamupp", sXpartamupp); | CFG_GET_VAL("lobby.xpartamupp", sXpartamupp); | ||||
CFG_GET_VAL("lobby.echelon", sEchelon); | CFG_GET_VAL("lobby.echelon", sEchelon); | ||||
Show All 35 Lines | XmppClient::XmppClient(const ScriptInterface* scriptInterface, const std::string& sUsername, const std::string& sPassword, const std::string& sRoom, const std::string& sNick, const int historyRequestSize, bool regOpt) | ||||
m_client->registerIqHandler(this, EXTBOARDLISTQUERY); | m_client->registerIqHandler(this, EXTBOARDLISTQUERY); | ||||
m_client->registerStanzaExtension(new ProfileQuery()); | m_client->registerStanzaExtension(new ProfileQuery()); | ||||
m_client->registerIqHandler(this, EXTPROFILEQUERY); | m_client->registerIqHandler(this, EXTPROFILEQUERY); | ||||
m_client->registerStanzaExtension(new LobbyAuth()); | m_client->registerStanzaExtension(new LobbyAuth()); | ||||
m_client->registerIqHandler(this, EXTLOBBYAUTH); | m_client->registerIqHandler(this, EXTLOBBYAUTH); | ||||
m_client->registerMessageHandler(this); | m_client->registerMessageHandler(this); | ||||
Not Done Inline ActionsDoes gloox take care of the ptr deletion? Stan: Does gloox take care of the ptr deletion? | |||||
Done Inline Actionsguess so. else we are in trouble already, but i ll check Silier: guess so. else we are in trouble already, but i ll check | |||||
// Uncomment to see the raw stanzas | // Uncomment to see the raw stanzas | ||||
//m_client->getWrapped()->logInstance().registerLogHandler( gloox::LogLevelDebug, gloox::LogAreaAll, this ); | //m_client->getWrapped()->logInstance().registerLogHandler( gloox::LogLevelDebug, gloox::LogAreaAll, this ); | ||||
if (!regOpt) | if (!regOpt) | ||||
{ | { | ||||
// Create a Multi User Chat Room | // Create a Multi User Chat Room | ||||
m_mucRoom = new glooxwrapper::MUCRoom(m_client, roomJid, this, 0); | m_mucRoom = new glooxwrapper::MUCRoom(m_client, roomJid, this, 0); | ||||
▲ Show 20 Lines • Show All 195 Lines • ▼ Show 20 Lines | void XmppClient::SendIqGetProfile(const std::string& player) | ||||
// Send IQ | // Send IQ | ||||
ProfileQuery* b = new ProfileQuery(); | ProfileQuery* b = new ProfileQuery(); | ||||
b->m_Command = player; | b->m_Command = player; | ||||
glooxwrapper::IQ iq(gloox::IQ::Get, echelonJid, m_client->getID()); | glooxwrapper::IQ iq(gloox::IQ::Get, echelonJid, m_client->getID()); | ||||
iq.addExtension(b); | iq.addExtension(b); | ||||
DbgXMPP("SendIqGetProfile [" << tag_xml(iq) << "]"); | DbgXMPP("SendIqGetProfile [" << tag_xml(iq) << "]"); | ||||
m_client->send(iq); | m_client->send(iq); | ||||
} | } | ||||
Done Inline ActionsDocumentation: Request the Connection data (ip, port...) from the server. wraitii: Documentation: Request the Connection data (ip, port...) from the server. | |||||
/** | /** | ||||
* Send game report containing numerous game properties to the server. | * Send game report containing numerous game properties to the server. | ||||
* | * | ||||
* @param data A JS array of game statistics | * @param data A JS array of game statistics | ||||
*/ | */ | ||||
Done Inline ActionsStrange naming. vladislavbelov: Strange naming. | |||||
void XmppClient::SendIqGameReport(const ScriptInterface& scriptInterface, JS::HandleValue data) | void XmppClient::SendIqGameReport(const ScriptInterface& scriptInterface, JS::HandleValue data) | ||||
{ | { | ||||
glooxwrapper::JID echelonJid(m_echelonId); | glooxwrapper::JID echelonJid(m_echelonId); | ||||
// Setup some base stanza attributes | // Setup some base stanza attributes | ||||
GameReport* game = new GameReport(); | GameReport* game = new GameReport(); | ||||
Done Inline Actions? Stan: ? | |||||
glooxwrapper::Tag* report = glooxwrapper::Tag::allocate("game"); | glooxwrapper::Tag* report = glooxwrapper::Tag::allocate("game"); | ||||
// Iterate through all the properties reported and add them to the stanza. | // Iterate through all the properties reported and add them to the stanza. | ||||
std::vector<std::string> properties; | std::vector<std::string> properties; | ||||
scriptInterface.EnumeratePropertyNames(data, true, properties); | scriptInterface.EnumeratePropertyNames(data, true, properties); | ||||
for (const std::string& p : properties) | for (const std::string& p : properties) | ||||
{ | { | ||||
std::wstring value; | std::wstring value; | ||||
scriptInterface.GetProperty(data, p.c_str(), value); | scriptInterface.GetProperty(data, p.c_str(), value); | ||||
report->addAttribute(p, utf8_from_wstring(value)); | report->addAttribute(p, utf8_from_wstring(value)); | ||||
} | } | ||||
// Add stanza to IQ | // Add stanza to IQ | ||||
game->m_GameReport.emplace_back(report); | game->m_GameReport.emplace_back(report); | ||||
// Send IQ | // Send IQ | ||||
glooxwrapper::IQ iq(gloox::IQ::Set, echelonJid, m_client->getID()); | glooxwrapper::IQ iq(gloox::IQ::Set, echelonJid, m_client->getID()); | ||||
iq.addExtension(game); | iq.addExtension(game); | ||||
DbgXMPP("SendGameReport [" << tag_xml(iq) << "]"); | DbgXMPP("SendGameReport [" << tag_xml(iq) << "]"); | ||||
m_client->send(iq); | m_client->send(iq); | ||||
}; | }; | ||||
std::string XmppClient::GetGameIp(const ScriptInterface& scriptInterface, const std::string& hostName, bool stun) | |||||
Done Inline Actionsnuke Silier: nuke | |||||
{ | |||||
ScriptRequest rq(scriptInterface); | |||||
for (const glooxwrapper::Tag* const& t : m_GameList) | |||||
{ | |||||
JS::RootedValue game(rq.cx); | |||||
ScriptInterface::CreateObject(rq, &game); | |||||
glooxwrapper::string userName = t->findAttribute("hostUsername"); | |||||
if (userName.to_string().compare(hostName) == 0) | |||||
Done Inline Actionsshould not be here Silier: should not be here | |||||
return t->findAttribute(stun ? "stunIP" : "ip").to_string(); | |||||
} | |||||
Done Inline Actionsif stunIP not empty, return, else return regular Silier: if stunIP not empty, return, else return regular
i also wonder why there are two if clearly one… | |||||
return ""; | |||||
} | |||||
/** | /** | ||||
* Send a request to register a game to the server. | * Send a request to register a game to the server. | ||||
* | * | ||||
* @param data A JS array of game attributes | * @param data A JS array of game attributes | ||||
*/ | */ | ||||
void XmppClient::SendIqRegisterGame(const ScriptInterface& scriptInterface, JS::HandleValue data) | void XmppClient::SendIqRegisterGame(const ScriptInterface& scriptInterface, JS::HandleValue data) | ||||
{ | { | ||||
glooxwrapper::JID xpartamuppJid(m_xpartamuppId); | glooxwrapper::JID xpartamuppJid(m_xpartamuppId); | ||||
▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | ||||
{ | { | ||||
ScriptRequest rq(scriptInterface); | ScriptRequest rq(scriptInterface); | ||||
ScriptInterface::CreateArray(rq, ret); | ScriptInterface::CreateArray(rq, ret); | ||||
int j = 0; | int j = 0; | ||||
const char* stats[] = { "name", "ip", "port", "stunIP", "stunPort", "hostUsername", "state", | const char* stats[] = { "name", "port", "stunPort", "hostUsername", "state", | ||||
Done Inline Actionsremove ports Silier: remove ports | |||||
"nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", | "nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", | ||||
"victoryConditions", "startTime", "mods" }; | "victoryConditions", "startTime", "mods" }; | ||||
for(const glooxwrapper::Tag* const& t : m_GameList) | for(const glooxwrapper::Tag* const& t : m_GameList) | ||||
{ | { | ||||
JS::RootedValue game(rq.cx); | JS::RootedValue game(rq.cx); | ||||
ScriptInterface::CreateObject(rq, &game); | ScriptInterface::CreateObject(rq, &game); | ||||
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) | for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) | ||||
scriptInterface.SetProperty(game, stats[i], t->findAttribute(stats[i])); | scriptInterface.SetProperty(game, stats[i], t->findAttribute(stats[i])); | ||||
scriptInterface.SetProperty(game, "useSTUN", !t->findAttribute("stunIP").empty()); | |||||
Done Inline Actionsnuke Silier: nuke | |||||
scriptInterface.SetPropertyInt(ret, j++, game); | scriptInterface.SetPropertyInt(ret, j++, game); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Handle requests from the GUI for leaderboard data. | * Handle requests from the GUI for leaderboard data. | ||||
* | * | ||||
* @return A JS array containing all known leaderboard data | * @return A JS array containing all known leaderboard data | ||||
▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/** | /** | ||||
* Handle portions of messages containing custom stanza extensions. | * Handle portions of messages containing custom stanza extensions. | ||||
*/ | */ | ||||
bool XmppClient::handleIq(const glooxwrapper::IQ& iq) | bool XmppClient::handleIq(const glooxwrapper::IQ& iq) | ||||
{ | { | ||||
DbgXMPP("handleIq [" << tag_xml(iq) << "]"); | DbgXMPP("handleIq [" << tag_xml(iq) << "]"); | ||||
Done Inline Actionsnuke Silier: nuke | |||||
if (iq.subtype() == gloox::IQ::Result) | if (iq.subtype() == gloox::IQ::Result) | ||||
{ | { | ||||
const GameListQuery* gq = iq.findExtension<GameListQuery>(EXTGAMELISTQUERY); | const GameListQuery* gq = iq.findExtension<GameListQuery>(EXTGAMELISTQUERY); | ||||
const BoardListQuery* bq = iq.findExtension<BoardListQuery>(EXTBOARDLISTQUERY); | const BoardListQuery* bq = iq.findExtension<BoardListQuery>(EXTBOARDLISTQUERY); | ||||
const ProfileQuery* pq = iq.findExtension<ProfileQuery>(EXTPROFILEQUERY); | const ProfileQuery* pq = iq.findExtension<ProfileQuery>(EXTPROFILEQUERY); | ||||
if (gq) | if (gq) | ||||
{ | { | ||||
for (const glooxwrapper::Tag* const& t : m_GameList) | for (const glooxwrapper::Tag* const& t : m_GameList) | ||||
glooxwrapper::Tag::free(t); | glooxwrapper::Tag::free(t); | ||||
Done Inline Actionsnuke Silier: nuke | |||||
m_GameList.clear(); | m_GameList.clear(); | ||||
for (const glooxwrapper::Tag* const& t : gq->m_GameList) | for (const glooxwrapper::Tag* const& t : gq->m_GameList) | ||||
m_GameList.emplace_back(t->clone()); | m_GameList.emplace_back(t->clone()); | ||||
Done Inline Actionstransform to gui message, Silier: transform to gui message,
make sure to cancel this properly | |||||
CreateGUIMessage("game", "gamelist", std::time(nullptr)); | CreateGUIMessage("game", "gamelist", std::time(nullptr)); | ||||
} | } | ||||
Not Done Inline ActionsWhy is it needed to do this check? wraitii: Why is it needed to do this check? | |||||
Done Inline Actionsbecause iq is identified by sender and its id, so we react only to the ones we asked and no-one can break us just by sending random answer Silier: because iq is identified by sender and its id, so we react only to the ones we asked and no-one… | |||||
Not Done Inline Actions👍 wraitii: 👍 | |||||
if (bq) | if (bq) | ||||
{ | { | ||||
if (bq->m_Command == "boardlist") | if (bq->m_Command == "boardlist") | ||||
{ | { | ||||
Not Done Inline ActionsI think it would be more logical to call PushGuiMessage directly. If you end up keeping the function, consider renaming it to HandleGetConnectionDataFailed, this makes it look like an FSM state but it's not one. wraitii: I think it would be more logical to call `PushGuiMessage` directly.
Presumably you should also… | |||||
Done Inline Actionsno, js is closing connection like in case of other error messages Silier: no, js is closing connection like in case of other error messages | |||||
Not Done Inline Actionsk I was wondering that. wraitii: k I was wondering that. | |||||
for (const glooxwrapper::Tag* const& t : m_BoardList) | for (const glooxwrapper::Tag* const& t : m_BoardList) | ||||
glooxwrapper::Tag::free(t); | glooxwrapper::Tag::free(t); | ||||
m_BoardList.clear(); | m_BoardList.clear(); | ||||
Done Inline Actionsgui message, cancel connecting properly Silier: gui message, cancel connecting properly | |||||
for (const glooxwrapper::Tag* const& t : bq->m_StanzaBoardList) | for (const glooxwrapper::Tag* const& t : bq->m_StanzaBoardList) | ||||
m_BoardList.emplace_back(t->clone()); | m_BoardList.emplace_back(t->clone()); | ||||
Done Inline Actionsuseless blank line wraitii: useless blank line | |||||
CreateGUIMessage("game", "leaderboard", std::time(nullptr)); | CreateGUIMessage("game", "leaderboard", std::time(nullptr)); | ||||
} | } | ||||
else if (bq->m_Command == "ratinglist") | else if (bq->m_Command == "ratinglist") | ||||
{ | { | ||||
for (const glooxwrapper::Tag* const& t : bq->m_StanzaBoardList) | for (const glooxwrapper::Tag* const& t : bq->m_StanzaBoardList) | ||||
{ | { | ||||
const PlayerMap::iterator it = m_PlayerMap.find(t->findAttribute("name")); | const PlayerMap::iterator it = m_PlayerMap.find(t->findAttribute("name")); | ||||
Show All 34 Lines | if (lobbyAuth) | ||||
LOGERROR("Received lobby authentication request, but not hosting currently!"); | LOGERROR("Received lobby authentication request, but not hosting currently!"); | ||||
} | } | ||||
} | } | ||||
else if (iq.subtype() == gloox::IQ::Error) | else if (iq.subtype() == gloox::IQ::Error) | ||||
CreateGUIMessage("system", "error", std::time(nullptr), "text", iq.error_error()); | CreateGUIMessage("system", "error", std::time(nullptr), "text", iq.error_error()); | ||||
else | else | ||||
{ | { | ||||
CreateGUIMessage("system", "error", std::time(nullptr), "text", wstring_from_utf8(g_L10n.Translate("unknown subtype (see logs)"))); | CreateGUIMessage("system", "error", std::time(nullptr), "text", wstring_from_utf8(g_L10n.Translate("unknown subtype (see logs)"))); | ||||
LOGMESSAGE("unknown subtype '%s'", tag_name(iq).c_str()); | LOGMESSAGE("unknown subtype '%s'", tag_name(iq).c_str()); | ||||
Done Inline Actionswant to log to mainlog Silier: want to log to mainlog | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* Update local data when a user changes presence. | * Update local data when a user changes presence. | ||||
*/ | */ | ||||
void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom& UNUSED(room), const glooxwrapper::MUCRoomParticipant participant, const glooxwrapper::Presence& presence) | void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom& UNUSED(room), const glooxwrapper::MUCRoomParticipant participant, const glooxwrapper::Presence& presence) | ||||
{ | { | ||||
const glooxwrapper::string& nick = participant.nick->resource(); | const glooxwrapper::string& nick = participant.nick->resource(); | ||||
if (presence.presence() == gloox::Presence::Unavailable) | if (presence.presence() == gloox::Presence::Unavailable) | ||||
{ | { | ||||
if (!participant.newNick.empty() && (participant.flags & (gloox::UserNickChanged | gloox::UserSelf))) | if (!participant.newNick.empty() && (participant.flags & (gloox::UserNickChanged | gloox::UserSelf))) | ||||
Done Inline Actionsthis is wrong, we need just public ip Silier: this is wrong, we need just public ip | |||||
{ | { | ||||
// we have a nick change | // we have a nick change | ||||
if (m_PlayerMap.find(participant.newNick) == m_PlayerMap.end()) | if (m_PlayerMap.find(participant.newNick) == m_PlayerMap.end()) | ||||
Done Inline Actionsnuke Silier: nuke | |||||
m_PlayerMap.emplace( | m_PlayerMap.emplace( | ||||
std::piecewise_construct, | std::piecewise_construct, | ||||
std::forward_as_tuple(participant.newNick), | std::forward_as_tuple(participant.newNick), | ||||
std::forward_as_tuple(presence.presence(), participant.role, std::move(m_PlayerMap.at(nick).m_Rating))); | std::forward_as_tuple(presence.presence(), participant.role, std::move(m_PlayerMap.at(nick).m_Rating))); | ||||
else | else | ||||
LOGERROR("Nickname changed to an existing nick!"); | LOGERROR("Nickname changed to an existing nick!"); | ||||
DbgXMPP(nick << " is now known as " << participant.newNick); | DbgXMPP(nick << " is now known as " << participant.newNick); | ||||
▲ Show 20 Lines • Show All 468 Lines • Show Last 20 Lines |
revert