Ticket #3832: t3832-fix-lobby-timestamps.diff

File t3832-fix-lobby-timestamps.diff, 8.8 KB (added by Josh, 8 years ago)

Rework lobby message timestamp handling (v2)

  • source/lobby/XmppClient.cpp

     
    592592        scriptInterface.SetProperty(ret, "level", message.level);
    593593    if (!message.data.empty())
    594594        scriptInterface.SetProperty(ret, "data", message.data);
    595     if (!message.datetime.empty())
    596         scriptInterface.SetProperty(ret, "datetime", message.datetime);
     595    scriptInterface.SetProperty(ret, "time", message.time);
    597596
    598597    m_GuiMessageQueue.pop_front();
    599598}
     
    655654    message.level = L"room-message";
    656655    message.from = wstring_from_utf8(msg.from().resource().to_string());
    657656    message.text = wstring_from_utf8(msg.body().to_string());
    658     if (msg.when())
    659         // See http://xmpp.org/extensions/xep-0082.html#sect-idp285136 for format
    660         message.datetime = msg.when()->stamp().to_string();
     657    message.time = ComputeTimestamp(msg);
    661658    PushGuiMessage(message);
    662659}
    663660
     
    674671    message.level = L"private-message";
    675672    message.from = wstring_from_utf8(msg.from().username().to_string());
    676673    message.text = wstring_from_utf8(msg.body().to_string());
    677     if (msg.when())
    678         //See http://xmpp.org/extensions/xep-0082.html#sect-idp285136 for format
    679         message.datetime = msg.when()->stamp().to_string();
     674    message.time = ComputeTimestamp(msg);
    680675    PushGuiMessage(message);
    681676}
    682677
     
    769764    message.level = wstring_from_utf8(level);
    770765    message.text = wstring_from_utf8(text);
    771766    message.data = wstring_from_utf8(data);
     767    message.time = time(NULL);
    772768    PushGuiMessage(message);
    773769}
    774770
     
    939935 *****************************************************/
    940936
    941937/**
     938 * Compute the POSIX timestamp of a message. Uses message datetime when possible, current time otherwise.
     939 *
     940 * @param msg The message on which to base the computation
     941 * @returns POSIX GMT/UTC seconds since Jan. 1st 1970
     942 */
     943time_t XmppClient::ComputeTimestamp(const glooxwrapper::Message& msg) {
     944    if (!msg.when())
     945        return time(NULL);
     946
     947    glooxwrapper::string timestampStr = msg.when()->stamp();
     948    struct tm timestamp = {0};
     949    // See http://xmpp.org/extensions/xep-0082.html#sect-idp285136 for format
     950    void * res = strptime(timestampStr.c_str(), "%Y-%m-%dT%H:%M:%SZ", &timestamp);
     951    if (res == NULL)
     952        LOGERROR("Recived delayed message with corrupted timestamp %s", timestampStr.to_string());
     953    // mktime returns localtime, so we have to re-adjust back to GMT/UTC
     954    return mktime(&timestamp) - timezone;
     955}
     956
     957/**
    942958 * Convert a gloox presence type to string.
    943959 *
    944960 * @param p Presence to be converted
  • source/lobby/XmppClient.h

     
    127127    std::string StanzaErrorToString(gloox::StanzaError err) const;
    128128    std::string ConnectionErrorToString(gloox::ConnectionError err) const;
    129129    std::string RegistrationResultToString(gloox::RegistrationResult res) const;
     130    time_t ComputeTimestamp(const glooxwrapper::Message& msg);
    130131
    131132public:
    132133    /* Messages */
     
    138139        std::wstring data;
    139140        std::wstring from;
    140141        std::wstring message;
    141         std::string datetime;
     142        time_t time;
    142143    };
    143144    void GuiPollMessage(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
    144145    void SendMUCMessage(const std::string& message);
    145146    void ClearPresenceUpdates();
    146147    int GetMucMessageCount();
    147     protected:
     148protected:
    148149    void PushGuiMessage(XmppClient::GUIMessage message);
    149150    void CreateGUIMessage(const std::string& type, const std::string& level, const std::string& text = "", const std::string& data = "");
    150151
  • binaries/data/mods/public/gui/lobby/lobby.js

     
    111111            updateLeaderboard();
    112112            updatePlayerList();
    113113            Engine.GetGUIObjectByName("hostButton").enabled = false;
    114             addChatMessage({ "from": "system", "text": translate("Disconnected.") + msg.text, "color": g_SystemColor });
     114            addChatMessage({
     115                "from": "system",
     116                "text": translate("Disconnected.") + msg.text,
     117                "color": g_SystemColor,
     118                "time": msg.time
     119            });
    115120        },
    116121        "error": msg => {
    117             addChatMessage({ "from": "system", "text": msg.text, "color": g_SystemColor });
     122            addChatMessage({ "from": "system", "text": msg.text, "color": g_SystemColor, "time": msg.time});
    118123        }
    119124    },
    120125    "chat": {
     
    124129        "join": msg => {
    125130            addChatMessage({
    126131                "text": "/special " + sprintf(translate("%(nick)s has joined."), { "nick": msg.text }),
    127                 "isSpecial": true
     132                "isSpecial": true,
     133                "time": msg.time
    128134            });
    129135            Engine.SendGetRatingList();
    130136        },
     
    131137        "leave": msg => {
    132138            addChatMessage({
    133139                "text": "/special " + sprintf(translate("%(nick)s has left."), { "nick": msg.text }),
    134                 "isSpecial": true
     140                "isSpecial": true,
     141                "time": msg.time
    135142            });
    136143        },
    137144        "presence": msg => {
     
    142149                    "oldnick": msg.text,
    143150                    "newnick": msg.data
    144151                }),
    145                 "isSpecial": true
     152                "isSpecial": true,
     153                "time": msg.time
    146154            });
    147155        },
    148156        "room-message": msg => {
     
    149157            addChatMessage({
    150158                "from": escapeText(msg.from),
    151159                "text": escapeText(msg.text),
    152                 "datetime": msg.datetime
     160                "time": msg.time
    153161            });
    154162        },
    155163        "private-message": msg => {
     
    157165                addChatMessage({
    158166                    "from": "(Private) " + escapeText(msg.from), // TODO: placeholder
    159167                    "text": escapeText(msg.text.trim()), // some XMPP clients send trailing whitespace
    160                     "datetime": msg.datetime
     168                    "time": msg.time
    161169                });
    162170        }
    163171    },
     
    656664            "text": sprintf(
    657665                translate("This game's address '%(ip)s' does not appear to be valid."),
    658666                { "ip": game.ip }
    659             )
     667            ),
     668            "time": Date.now() / 1000
    660669        });
    661670        return;
    662671    }
     
    767776    default:
    768777        addChatMessage({
    769778            "from": "system",
    770             "text": sprintf(translate("We're sorry, the '%(cmd)s' command is not supported."), { "cmd": cmd })
     779            "text": sprintf(translate("We're sorry, the '%(cmd)s' command is not supported."), { "cmd": cmd }),
     780            "time": Date.now() / 1000
    771781        });
    772782    }
    773783    return true;
     
    789799        if (g_Username != msg.from)
    790800            msg.text = msg.text.replace(g_Username, colorPlayerName(g_Username));
    791801
    792         // Run spam test if it's not a historical message
    793         if (!msg.datetime)
    794         {
    795             updateSpamMonitor(msg.from);
    796             if (isSpam(msg.text, msg.from))
    797                 return;
    798         }
     802        updateSpamMonitor(msg);
     803        if (isSpam(msg.text, msg.from))
     804            return;
    799805    }
    800806
    801807    var formatted = ircFormat(msg);
     
    877883    if (!g_ShowTimestamp)
    878884        return formattedMessage;
    879885
    880     var time;
    881     if (msg.datetime)
    882     {
    883         let dTime = msg.datetime.split("T");
    884         let parserDate = dTime[0].split("-");
    885         let parserTime = dTime[1].split(":");
    886         // See http://xmpp.org/extensions/xep-0082.html#sect-idp285136 for format of datetime
    887         // Date takes Year, Month, Day, Hour, Minute, Second
    888         time = new Date(Date.UTC(parserDate[0], parserDate[1], parserDate[2], parserTime[0], parserTime[1], parserTime[2].split("Z")[0]));
    889     }
    890     else
    891         time = new Date(Date.now());
    892 
    893886    // Translation: Time as shown in the multiplayer lobby (when you enable it in the options page).
    894887    // For a list of symbols that you can use, see:
    895888    // https://sites.google.com/site/icuprojectuserguide/formatparse/datetime?pli=1#TOC-Date-Field-Symbol-Table
    896     var timeString = Engine.FormatMillisecondsIntoDateString(time.getTime(), translate("HH:mm"));
     889    var timeString = Engine.FormatMillisecondsIntoDateString(msg.time * 1000, translate("HH:mm"));
    897890
    898891    // Translation: Time prefix as shown in the multiplayer lobby (when you enable it in the options page).
    899892    var timePrefixString = '[font="' + g_SenderFont + '"]' + sprintf(translate("\\[%(time)s]"), { "time": timeString }) + '[/font]';
     
    905898/**
    906899 * Update the spam monitor.
    907900 *
    908  * @param {string} from - User to update.
     901 * @param {Object} msg - Message containing user to update.
    909902 */
    910 function updateSpamMonitor(from)
     903function updateSpamMonitor(msg)
    911904{
    912     if (g_SpamMonitor[from])
    913         ++g_SpamMonitor[from][0];
     905    // Ignore historical messages (older than 5s)
     906    // TODO: Properly check for spam in historical messages as well
     907    if (msg.time < Date.now() / 1000 - 5)
     908        return;
     909
     910    if (g_SpamMonitor[msg.from])
     911        ++g_SpamMonitor[msg.from][0];
    914912    else
    915         g_SpamMonitor[from] = [1, Math.floor(Date.now() / 1000), 0];
     913        g_SpamMonitor[msg.from] = [1, Math.floor(Date.now() / 1000), 0];
    916914}
    917915
    918916/**
     
    945943    {
    946944        g_SpamMonitor[from][2] = time;
    947945        if (from == g_Username)
    948             addChatMessage({ "from": "system", "text": translate("Please do not spam. You have been blocked for thirty seconds.") });
     946            addChatMessage({
     947                "from": "system",
     948                "text": translate("Please do not spam. You have been blocked for thirty seconds."),
     949                "time": Date.now() / 1000
     950            });
    949951        return true;
    950952    }
    951953