XmppClient cleanup.

Allow XmppClient to use arbitrary property names in GUIMessages.
Remove duplication by calling CreateGUIMessage when receiving chat
messages.
Inline PushGUINotification.
Use std::string in the GUIMessage because every data source is of that
type.
Apply the wstring_from_utf8 conversion to ensure correct display of less
common UTF characters instead in the GuiPollMessage method.
Add room subject change chat message.

Differential Revision: https://code.wildfiregames.com/D835
Refs #4482
Comments by fpre, Vladislav and leper

This was SVN commit r20064.
This commit is contained in:
elexis 2017-08-28 17:47:43 +00:00
parent 6861588371
commit 0940db3fc0
4 changed files with 106 additions and 107 deletions

View File

@ -135,7 +135,7 @@ var g_NetMessageTypes = {
addChatMessage({
"from": "system",
"time": msg.time,
"text": translate("Disconnected.") + " " + msg.text
"text": translate("Disconnected.") + " " + msg.reason
});
return true;
},
@ -150,13 +150,23 @@ var g_NetMessageTypes = {
},
"chat": {
"subject": msg => {
updateSubject(msg.text);
updateSubject(msg.subject);
if (msg.nick)
addChatMessage({
"text": "/special " + sprintf(translate("%(nick)s changed the lobby subject to %(subject)s"), {
"nick": msg.nick,
"subject": msg.subject
}),
"time": msg.time,
"isSpecial": true
});
return false;
},
"join": msg => {
addChatMessage({
"text": "/special " + sprintf(translate("%(nick)s has joined."), {
"nick": msg.text
"nick": msg.nick
}),
"time": msg.time,
"isSpecial": true
@ -166,13 +176,13 @@ var g_NetMessageTypes = {
"leave": msg => {
addChatMessage({
"text": "/special " + sprintf(translate("%(nick)s has left."), {
"nick": msg.text
"nick": msg.nick
}),
"time": msg.time,
"isSpecial": true
});
if (msg.text == g_Username)
if (msg.nick == g_Username)
Engine.DisconnectXmppClient();
return true;
@ -181,18 +191,18 @@ var g_NetMessageTypes = {
"role": msg => {
Engine.GetGUIObjectByName("chatInput").hidden = Engine.LobbyGetPlayerRole(g_Username) == "visitor";
let me = g_Username == msg.text;
let role = Engine.LobbyGetPlayerRole(msg.text);
let me = g_Username == msg.nick;
let newrole = Engine.LobbyGetPlayerRole(msg.nick);
let txt =
role == "visitor" ?
newrole == "visitor" ?
me ?
translate("You have been muted.") :
translate("%(nick)s has been muted.") :
role == "moderator" ?
newrole == "moderator" ?
me ?
translate("You are now a moderator.") :
translate("%(nick)s is now a moderator.") :
msg.data == "visitor" ?
msg.oldrole == "visitor" ?
me ?
translate("You have been unmuted.") :
translate("%(nick)s has been unmuted.") :
@ -201,12 +211,12 @@ var g_NetMessageTypes = {
translate("%(nick)s is not a moderator anymore.");
addChatMessage({
"text": "/special " + sprintf(txt, { "nick": msg.text }),
"text": "/special " + sprintf(txt, { "nick": msg.nick }),
"time": msg.time,
"isSpecial": true
});
if (g_SelectedPlayer == msg.text)
if (g_SelectedPlayer == msg.nick)
updateUserRoleText(g_SelectedPlayer);
return false;
@ -214,8 +224,8 @@ var g_NetMessageTypes = {
"nick": msg => {
addChatMessage({
"text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), {
"oldnick": msg.text,
"newnick": msg.data
"oldnick": msg.oldnick,
"newnick": msg.newnick
}),
"time": msg.time,
"isSpecial": true
@ -223,11 +233,11 @@ var g_NetMessageTypes = {
return true;
},
"kicked": msg => {
handleKick(false, msg.text, msg.data || "", msg.time);
handleKick(false, msg.nick, msg.reason, msg.time);
return true;
},
"banned": msg => {
handleKick(true, msg.text, msg.data || "", msg.time);
handleKick(true, msg.nick, msg.reason, msg.time);
return true;
},
"room-message": msg => {
@ -550,8 +560,6 @@ function handleKick(banned, nick, reason, time)
/**
* Update the subject GUI object.
*
* @param {string} newSubject
*/
function updateSubject(newSubject)
{

View File

@ -162,11 +162,18 @@ function onTick()
g_LobbyIsConnecting = false;
switch(message.level) {
switch (message.level)
{
case "error":
{
Engine.GetGUIObjectByName("feedback").caption = message.text;
g_DisplayingSystemMessage = true;
Engine.StopXmppClient();
break;
}
case "disconnected":
{
Engine.GetGUIObjectByName("feedback").caption = message.text ||
Engine.GetGUIObjectByName("feedback").caption = message.reason ||
translate("Unknown error. This usually occurs because the same IP address is not allowed to register more than one account within one hour.");
g_DisplayingSystemMessage = true;
Engine.StopXmppClient();

View File

@ -140,7 +140,6 @@ XmppClient::XmppClient(const std::string& sUsername, const std::string& sPasswor
m_sessionManager = new glooxwrapper::SessionManager(m_client, this);
// Register plugins to allow gloox parse them in incoming sessions
m_sessionManager->registerPlugins();
}
/**
@ -231,7 +230,7 @@ void XmppClient::onDisconnect(gloox::ConnectionError error)
m_PlayerMap.clear();
m_Profile.clear();
CreateGUIMessage("system", "disconnected", ConnectionErrorToString(error));
CreateGUIMessage("system", "disconnected", "reason", ConnectionErrorToString(error));
}
/**
@ -257,7 +256,7 @@ bool XmppClient::onTLSConnect(const glooxwrapper::CertInfo& info)
*/
void XmppClient::handleMUCError(glooxwrapper::MUCRoom*, gloox::StanzaError err)
{
CreateGUIMessage("system", "error", StanzaErrorToString(err));
CreateGUIMessage("system", "error", "text", StanzaErrorToString(err));
}
/*****************************************************
@ -425,7 +424,8 @@ void XmppClient::handleRegistrationResult(const glooxwrapper::JID&, gloox::Regis
if (result == gloox::RegistrationSuccess)
CreateGUIMessage("system", "registered");
else
CreateGUIMessage("system", "error", RegistrationResultToString(result));
CreateGUIMessage("system", "error", "text", RegistrationResultToString(result));
disconnect();
}
@ -549,9 +549,26 @@ void XmppClient::GUIGetProfile(const ScriptInterface& scriptInterface, JS::Mutab
* Message interfaces *
*****************************************************/
/**
* Send GUI message queue when queried.
*/
void XmppClient::CreateGUIMessage(
const std::string& type,
const std::string& level,
const std::string& property1_name,
const std::string& property1_value,
const std::string& property2_name,
const std::string& property2_value,
const std::time_t time)
{
GUIMessage message;
message.type = type;
message.level = level;
message.property1_name = property1_name;
message.property1_value = property1_value;
message.property2_name = property2_name;
message.property2_value = property2_value;
message.time = time;
m_GuiMessageQueue.push_back(std::move(message));
}
void XmppClient::GuiPollMessage(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret)
{
if (m_GuiMessageQueue.empty())
@ -565,18 +582,14 @@ void XmppClient::GuiPollMessage(const ScriptInterface& scriptInterface, JS::Muta
JSAutoRequest rq(cx);
scriptInterface.Eval("({})", ret);
scriptInterface.SetProperty(ret, "type", message.type);
if (!message.from.empty())
scriptInterface.SetProperty(ret, "from", message.from);
if (!message.text.empty())
scriptInterface.SetProperty(ret, "text", message.text);
scriptInterface.SetProperty(ret, "type", wstring_from_utf8(message.type));
if (!message.level.empty())
scriptInterface.SetProperty(ret, "level", message.level);
if (!message.data.empty())
scriptInterface.SetProperty(ret, "data", message.data);
scriptInterface.SetProperty(ret, "level", wstring_from_utf8(message.level));
if (!message.property1_name.empty())
scriptInterface.SetProperty(ret, message.property1_name.c_str(), wstring_from_utf8(message.property1_value));
if (!message.property2_name.empty())
scriptInterface.SetProperty(ret, message.property2_name.c_str(), wstring_from_utf8(message.property2_value));
scriptInterface.SetProperty(ret, "time", (double)message.time);
m_GuiMessageQueue.pop_front();
}
@ -588,16 +601,6 @@ void XmppClient::SendMUCMessage(const std::string& message)
m_mucRoom->send(message);
}
/**
* Push a message onto the GUI queue.
*
* @param message Message to add to the queue
*/
void XmppClient::PushGuiMessage(XmppClient::GUIMessage message)
{
m_GuiMessageQueue.push_back(std::move(message));
}
/**
* Clears all presence updates from the message queue.
* Used when rejoining the lobby, since we don't need to handle past presence changes.
@ -608,7 +611,7 @@ void XmppClient::ClearPresenceUpdates()
std::remove_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(),
[](XmppClient::GUIMessage& message)
{
return message.type == L"chat" && message.level == L"presence";
return message.type == "chat" && message.level == "presence";
}
), m_GuiMessageQueue.end());
}
@ -620,30 +623,28 @@ void XmppClient::handleMUCMessage(glooxwrapper::MUCRoom*, const glooxwrapper::Me
{
DbgXMPP(msg.from().resource() << " said " << msg.body());
GUIMessage message;
message.type = L"chat";
message.level = priv ? L"private-message" : L"room-message";
message.from = wstring_from_utf8(msg.from().resource().to_string());
message.text = wstring_from_utf8(msg.body().to_string());
message.time = ComputeTimestamp(msg);
PushGuiMessage(message);
CreateGUIMessage(
"chat",
priv ? "private-message" : "room-message",
"from", msg.from().resource().to_string(),
"text", msg.body().to_string(),
ComputeTimestamp(msg));
}
/**
* Handle a private message.
*/
void XmppClient::handleMessage(const glooxwrapper::Message& msg, glooxwrapper::MessageSession *)
void XmppClient::handleMessage(const glooxwrapper::Message& msg, glooxwrapper::MessageSession*)
{
DbgXMPP("type " << msg.subtype() << ", subject " << msg.subject()
<< ", message " << msg.body() << ", thread id " << msg.thread());
GUIMessage message;
message.type = L"chat";
message.level = L"private-message";
message.from = wstring_from_utf8(msg.from().username().to_string());
message.text = wstring_from_utf8(msg.body().to_string());
message.time = ComputeTimestamp(msg);
PushGuiMessage(message);
CreateGUIMessage(
"chat",
"private-message",
"from", msg.from().resource().to_string(),
"text", msg.body().to_string(),
ComputeTimestamp(msg));
}
/**
@ -707,38 +708,15 @@ bool XmppClient::handleIq(const glooxwrapper::IQ& iq)
}
}
else if (iq.subtype() == gloox::IQ::Error)
{
gloox::StanzaError err = iq.error_error();
CreateGUIMessage("system", "error", StanzaErrorToString(err));
}
CreateGUIMessage("system", "error", "text", StanzaErrorToString(iq.error_error()));
else
{
CreateGUIMessage("system", "error", g_L10n.Translate("unknown subtype (see logs)"));
std::string tag = tag_name(iq);
LOGMESSAGE("unknown subtype '%s'", tag.c_str());
CreateGUIMessage("system", "error", "text", g_L10n.Translate("unknown subtype (see logs)"));
LOGMESSAGE("unknown subtype '%s'", tag_name(iq).c_str());
}
return true;
}
/**
* Create a new detail message for the GUI.
*
* @param type General message type
* @param level Detailed message type
* @param text Body of the message
* @param data Optional field, used for auxiliary data
*/
void XmppClient::CreateGUIMessage(const std::string& type, const std::string& level, const std::string& text, const std::string& data)
{
GUIMessage message;
message.type = wstring_from_utf8(type);
message.level = wstring_from_utf8(level);
message.text = wstring_from_utf8(text);
message.data = wstring_from_utf8(data);
message.time = std::time(nullptr);
PushGuiMessage(message);
}
/*****************************************************
* Presence, nickname, and subject *
*****************************************************/
@ -763,25 +741,25 @@ void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom*, const gloo
m_PlayerMap[newNick].resize(3);
m_PlayerMap[newNick][0] = presenceString;
m_PlayerMap[newNick][2] = roleString;
CreateGUIMessage("chat", "nick", nick, participant.newNick.to_string());
DbgXMPP(nick << " is now known as " << participant.newNick.to_string());
CreateGUIMessage("chat", "nick", "oldnick", nick, "newnick", participant.newNick.to_string());
}
else if (participant.flags & gloox::UserKicked)
{
DbgXMPP(nick << " was kicked. Reason: " << participant.reason.to_string());
CreateGUIMessage("chat", "kicked", nick, participant.reason.to_string());
CreateGUIMessage("chat", "kicked", "nick", nick, "reason", participant.reason.to_string());
}
else if (participant.flags & gloox::UserBanned)
{
DbgXMPP(nick << " was banned. Reason: " << participant.reason.to_string());
CreateGUIMessage("chat", "banned", nick, participant.reason.to_string());
CreateGUIMessage("chat", "banned", "nick", nick, "reason", participant.reason.to_string());
}
else
{
DbgXMPP(nick << " left the room (flags " << participant.flags << ")");
CreateGUIMessage("chat", "leave", nick);
CreateGUIMessage("chat", "leave", "nick", nick);
}
m_PlayerMap.erase(nick);
}
else
@ -796,11 +774,11 @@ void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom*, const gloo
m_initialLoadComplete = true;
}
else if (m_PlayerMap.find(nick) == m_PlayerMap.end())
CreateGUIMessage("chat", "join", nick);
CreateGUIMessage("chat", "join", "nick", nick);
else if (m_PlayerMap[nick][2] != roleString)
CreateGUIMessage("chat", "role", nick, m_PlayerMap[nick][2]);
CreateGUIMessage("chat", "role", "nick", nick, "oldrole", m_PlayerMap[nick][2]);
else
CreateGUIMessage("chat", "presence", nick);
CreateGUIMessage("chat", "presence", "nick", nick);
DbgXMPP(nick << " is in the room, presence : " << (int)presenceType);
m_PlayerMap[nick].resize(3);
@ -812,10 +790,10 @@ void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom*, const gloo
/**
* Update local cache when subject changes.
*/
void XmppClient::handleMUCSubject(glooxwrapper::MUCRoom*, const glooxwrapper::string& UNUSED(nick), const glooxwrapper::string& subject)
void XmppClient::handleMUCSubject(glooxwrapper::MUCRoom*, const glooxwrapper::string& nick, const glooxwrapper::string& subject)
{
m_Subject = subject.c_str();
CreateGUIMessage("chat", "subject", m_Subject);
CreateGUIMessage("chat", "subject", "nick", nick.c_str(), "subject", m_Subject);
}
/**

View File

@ -135,20 +135,26 @@ public:
/* Messages */
struct GUIMessage
{
std::wstring type;
std::wstring level;
std::wstring text;
std::wstring data;
std::wstring from;
std::wstring message;
std::string type;
std::string level;
std::string property1_name;
std::string property1_value;
std::string property2_name;
std::string property2_value;
std::time_t time;
};
void GuiPollMessage(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
void SendMUCMessage(const std::string& message);
void ClearPresenceUpdates();
protected:
void PushGuiMessage(XmppClient::GUIMessage message);
void CreateGUIMessage(const std::string& type, const std::string& level, const std::string& text = "", const std::string& data = "");
void CreateGUIMessage(
const std::string& type,
const std::string& level = "",
const std::string& property1_name = "",
const std::string& property1_value = "",
const std::string& property2_name = "",
const std::string& property2_value = "",
const std::time_t time = std::time_t(nullptr));
private:
/// Map of players