diff --git a/client/serverLobby/LobbyWindow.cpp b/client/serverLobby/LobbyWindow.cpp index 7f670b58d..858858ab9 100644 --- a/client/serverLobby/LobbyWindow.cpp +++ b/client/serverLobby/LobbyWindow.cpp @@ -14,9 +14,10 @@ #include "../gui/CGuiHandler.h" #include "../gui/WindowHandler.h" #include "../widgets/TextControls.h" - #include "../windows/InfoWindows.h" +#include "../../lib/MetaString.h" + LobbyClient::LobbyClient(LobbyWindow * window) : window(window) { @@ -25,7 +26,33 @@ LobbyClient::LobbyClient(LobbyWindow * window) void LobbyClient::onPacketReceived(const std::vector & message) { + // FIXME: find better approach + const char * payloadBegin = reinterpret_cast(message.data()); + JsonNode json(payloadBegin, message.size()); + if (json["type"].String() == "chatHistory") + { + for (auto const & entry : json["messages"].Vector()) + { + std::string senderName = entry["senderName"].String(); + std::string messageText = entry["messageText"].String(); + int ageSeconds = entry["ageSeconds"].Integer(); + + // FIXME: better/unified way to format date + auto timeNowChrono = std::chrono::system_clock::now(); + timeNowChrono -= std::chrono::seconds(ageSeconds); + + std::time_t timeNowC = std::chrono::system_clock::to_time_t(timeNowChrono); + std::tm timeNowTm = *std::localtime(&timeNowC); + + MetaString dateFormatted; + dateFormatted.appendRawString("%d:%d"); + dateFormatted.replaceNumber(timeNowTm.tm_hour); + dateFormatted.replaceNumber(timeNowTm.tm_min); + + window->onGameChatMessage(senderName, messageText, dateFormatted.toString()); + } + } } void LobbyClient::onConnectionFailed(const std::string & errorMessage) @@ -68,6 +95,11 @@ std::shared_ptr LobbyWidget::getMessageInput() return widget("messageInput"); } +std::shared_ptr LobbyWidget::getGameChat() +{ + return widget("gameChat"); +} + LobbyWindow::LobbyWindow(): CWindowObject(BORDERED) { @@ -99,3 +131,16 @@ void LobbyWindow::doSendChatMessage() widget->getMessageInput()->setText(""); } + +void LobbyWindow::onGameChatMessage(const std::string & sender, const std::string & message, const std::string & when) +{ + MetaString chatMessageFormatted; + chatMessageFormatted.appendRawString("[%s] {%s}: %s\n"); + chatMessageFormatted.replaceRawString(when); + chatMessageFormatted.replaceRawString(sender); + chatMessageFormatted.replaceRawString(message); + + chatHistory += chatMessageFormatted.toString(); + + widget->getGameChat()->setText(chatHistory); +} diff --git a/client/serverLobby/LobbyWindow.h b/client/serverLobby/LobbyWindow.h index 0aaf96b6a..7fe54a001 100644 --- a/client/serverLobby/LobbyWindow.h +++ b/client/serverLobby/LobbyWindow.h @@ -23,6 +23,7 @@ public: LobbyWidget(LobbyWindow * window); std::shared_ptr getMessageInput(); + std::shared_ptr getGameChat(); }; class LobbyClient : public NetworkClient @@ -41,6 +42,8 @@ public: class LobbyWindow : public CWindowObject { + std::string chatHistory; + std::shared_ptr widget; std::shared_ptr connection; @@ -51,5 +54,5 @@ public: void doSendChatMessage(); - void onGameChatMessage(std::string sender, std::string message, std::string when); + void onGameChatMessage(const std::string & sender, const std::string & message, const std::string & when); }; diff --git a/lib/network/NetworkServer.cpp b/lib/network/NetworkServer.cpp index 7e201c83f..157a68958 100644 --- a/lib/network/NetworkServer.cpp +++ b/lib/network/NetworkServer.cpp @@ -43,6 +43,7 @@ void NetworkServer::connectionAccepted(std::shared_ptr upcomingCo auto connection = std::make_shared(upcomingConnection, *this); connections.insert(connection); connection->start(); + onNewConnection(connection); startAsyncAccept(); } diff --git a/lobby/LobbyServer.cpp b/lobby/LobbyServer.cpp index 3aae7ba45..be69c74ce 100644 --- a/lobby/LobbyServer.cpp +++ b/lobby/LobbyServer.cpp @@ -28,7 +28,16 @@ void LobbyDatabase::prepareStatements() INSERT INTO chatMessages(senderName, messageText) VALUES( ?, ?); )"; + static const std::string getRecentMessageHistoryText = R"( + SELECT senderName, messageText, strftime('%s',CURRENT_TIMESTAMP)- strftime('%s',sendTime) AS secondsElapsed + FROM chatMessages + WHERE secondsElapsed < 60*60*24 + ORDER BY sendTime DESC + LIMIT 100 + )"; + insertChatMessageStatement = database->prepare(insertChatMessageText); + getRecentMessageHistoryStatement = database->prepare(getRecentMessageHistoryText); } void LobbyDatabase::createTableChatMessages() @@ -69,9 +78,55 @@ void LobbyDatabase::insertChatMessage(const std::string & sender, const std::str insertChatMessageStatement->reset(); } -void LobbyServer::onNewConnection(const std::shared_ptr &) +std::vector LobbyDatabase::getRecentMessageHistory() { + std::vector result; + while(getRecentMessageHistoryStatement->execute()) + { + LobbyDatabase::ChatMessage message; + getRecentMessageHistoryStatement->getColumns(message.sender, message.messageText, message.messageAgeSeconds); + result.push_back(message); + } + getRecentMessageHistoryStatement->reset(); + + return result; +} + +void LobbyServer::sendMessage(const std::shared_ptr & target, const JsonNode & json) +{ + //FIXME: copy-paste from LobbyClient::sendMessage + std::string payloadString = json.toJson(true); + + // FIXME: find better approach + uint8_t * payloadBegin = reinterpret_cast(payloadString.data()); + uint8_t * payloadEnd = payloadBegin + payloadString.size(); + + std::vector payloadBuffer(payloadBegin, payloadEnd); + + sendPacket(target, payloadBuffer); +} + +void LobbyServer::onNewConnection(const std::shared_ptr & connection) +{ + // FIXME: move to authorization message reply + auto history = database->getRecentMessageHistory(); + + JsonNode json; + json["type"].String() = "chatHistory"; + + for (auto const & message : boost::adaptors::reverse(history)) + { + JsonNode jsonEntry; + + jsonEntry["messageText"].String() = message.messageText; + jsonEntry["senderName"].String() = message.sender; + jsonEntry["ageSeconds"].Integer() = message.messageAgeSeconds; + + json["messages"].Vector().push_back(jsonEntry); + } + + sendMessage(connection, json); } void LobbyServer::onPacketReceived(const std::shared_ptr &, const std::vector & message) diff --git a/lobby/LobbyServer.h b/lobby/LobbyServer.h index f7114e6c4..8e42a6248 100644 --- a/lobby/LobbyServer.h +++ b/lobby/LobbyServer.h @@ -11,6 +11,10 @@ #include "../lib/network/NetworkServer.h" +VCMI_LIB_NAMESPACE_BEGIN +class JsonNode; +VCMI_LIB_NAMESPACE_END + class SQLiteInstance; class SQLiteStatement; @@ -18,14 +22,23 @@ class LobbyDatabase { std::unique_ptr database; std::unique_ptr insertChatMessageStatement; + std::unique_ptr getRecentMessageHistoryStatement; void initializeDatabase(); void prepareStatements(); void createTableChatMessages(); public: + struct ChatMessage + { + std::string sender; + std::string messageText; + int messageAgeSeconds; + }; + LobbyDatabase(); void insertChatMessage(const std::string & sender, const std::string & messageText); + std::vector getRecentMessageHistory(); }; class LobbyServer : public NetworkServer @@ -34,6 +47,8 @@ class LobbyServer : public NetworkServer void onNewConnection(const std::shared_ptr &) override; void onPacketReceived(const std::shared_ptr &, const std::vector & message) override; + + void sendMessage(const std::shared_ptr & target, const JsonNode & json); public: LobbyServer(); };