1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Implemented loading of latest messages on joining chat

This commit is contained in:
Ivan Savenko 2023-11-12 16:35:53 +02:00
parent f10b6df989
commit 07fb313765
5 changed files with 122 additions and 3 deletions

View File

@ -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<uint8_t> & message)
{
// FIXME: find better approach
const char * payloadBegin = reinterpret_cast<const char*>(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<CTextInput> LobbyWidget::getMessageInput()
return widget<CTextInput>("messageInput");
}
std::shared_ptr<CTextBox> LobbyWidget::getGameChat()
{
return widget<CTextBox>("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);
}

View File

@ -23,6 +23,7 @@ public:
LobbyWidget(LobbyWindow * window);
std::shared_ptr<CTextInput> getMessageInput();
std::shared_ptr<CTextBox> getGameChat();
};
class LobbyClient : public NetworkClient
@ -41,6 +42,8 @@ public:
class LobbyWindow : public CWindowObject
{
std::string chatHistory;
std::shared_ptr<LobbyWidget> widget;
std::shared_ptr<LobbyClient> 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);
};

View File

@ -43,6 +43,7 @@ void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingCo
auto connection = std::make_shared<NetworkConnection>(upcomingConnection, *this);
connections.insert(connection);
connection->start();
onNewConnection(connection);
startAsyncAccept();
}

View File

@ -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<NetworkConnection> &)
std::vector<LobbyDatabase::ChatMessage> LobbyDatabase::getRecentMessageHistory()
{
std::vector<LobbyDatabase::ChatMessage> 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<NetworkConnection> & 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<uint8_t*>(payloadString.data());
uint8_t * payloadEnd = payloadBegin + payloadString.size();
std::vector<uint8_t> payloadBuffer(payloadBegin, payloadEnd);
sendPacket(target, payloadBuffer);
}
void LobbyServer::onNewConnection(const std::shared_ptr<NetworkConnection> & 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<NetworkConnection> &, const std::vector<uint8_t> & message)

View File

@ -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<SQLiteInstance> database;
std::unique_ptr<SQLiteStatement> insertChatMessageStatement;
std::unique_ptr<SQLiteStatement> 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<ChatMessage> getRecentMessageHistory();
};
class LobbyServer : public NetworkServer
@ -34,6 +47,8 @@ class LobbyServer : public NetworkServer
void onNewConnection(const std::shared_ptr<NetworkConnection> &) override;
void onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message) override;
void sendMessage(const std::shared_ptr<NetworkConnection> & target, const JsonNode & json);
public:
LobbyServer();
};