mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-27 22:49:25 +02:00
Implemented loading of latest messages on joining chat
This commit is contained in:
@@ -14,9 +14,10 @@
|
|||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
#include "../gui/WindowHandler.h"
|
#include "../gui/WindowHandler.h"
|
||||||
#include "../widgets/TextControls.h"
|
#include "../widgets/TextControls.h"
|
||||||
|
|
||||||
#include "../windows/InfoWindows.h"
|
#include "../windows/InfoWindows.h"
|
||||||
|
|
||||||
|
#include "../../lib/MetaString.h"
|
||||||
|
|
||||||
LobbyClient::LobbyClient(LobbyWindow * window)
|
LobbyClient::LobbyClient(LobbyWindow * window)
|
||||||
: window(window)
|
: window(window)
|
||||||
{
|
{
|
||||||
@@ -25,7 +26,33 @@ LobbyClient::LobbyClient(LobbyWindow * window)
|
|||||||
|
|
||||||
void LobbyClient::onPacketReceived(const std::vector<uint8_t> & message)
|
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)
|
void LobbyClient::onConnectionFailed(const std::string & errorMessage)
|
||||||
@@ -68,6 +95,11 @@ std::shared_ptr<CTextInput> LobbyWidget::getMessageInput()
|
|||||||
return widget<CTextInput>("messageInput");
|
return widget<CTextInput>("messageInput");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<CTextBox> LobbyWidget::getGameChat()
|
||||||
|
{
|
||||||
|
return widget<CTextBox>("gameChat");
|
||||||
|
}
|
||||||
|
|
||||||
LobbyWindow::LobbyWindow():
|
LobbyWindow::LobbyWindow():
|
||||||
CWindowObject(BORDERED)
|
CWindowObject(BORDERED)
|
||||||
{
|
{
|
||||||
@@ -99,3 +131,16 @@ void LobbyWindow::doSendChatMessage()
|
|||||||
|
|
||||||
widget->getMessageInput()->setText("");
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public:
|
|||||||
LobbyWidget(LobbyWindow * window);
|
LobbyWidget(LobbyWindow * window);
|
||||||
|
|
||||||
std::shared_ptr<CTextInput> getMessageInput();
|
std::shared_ptr<CTextInput> getMessageInput();
|
||||||
|
std::shared_ptr<CTextBox> getGameChat();
|
||||||
};
|
};
|
||||||
|
|
||||||
class LobbyClient : public NetworkClient
|
class LobbyClient : public NetworkClient
|
||||||
@@ -41,6 +42,8 @@ public:
|
|||||||
|
|
||||||
class LobbyWindow : public CWindowObject
|
class LobbyWindow : public CWindowObject
|
||||||
{
|
{
|
||||||
|
std::string chatHistory;
|
||||||
|
|
||||||
std::shared_ptr<LobbyWidget> widget;
|
std::shared_ptr<LobbyWidget> widget;
|
||||||
std::shared_ptr<LobbyClient> connection;
|
std::shared_ptr<LobbyClient> connection;
|
||||||
|
|
||||||
@@ -51,5 +54,5 @@ public:
|
|||||||
|
|
||||||
void doSendChatMessage();
|
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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingCo
|
|||||||
auto connection = std::make_shared<NetworkConnection>(upcomingConnection, *this);
|
auto connection = std::make_shared<NetworkConnection>(upcomingConnection, *this);
|
||||||
connections.insert(connection);
|
connections.insert(connection);
|
||||||
connection->start();
|
connection->start();
|
||||||
|
onNewConnection(connection);
|
||||||
startAsyncAccept();
|
startAsyncAccept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,16 @@ void LobbyDatabase::prepareStatements()
|
|||||||
INSERT INTO chatMessages(senderName, messageText) VALUES( ?, ?);
|
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);
|
insertChatMessageStatement = database->prepare(insertChatMessageText);
|
||||||
|
getRecentMessageHistoryStatement = database->prepare(getRecentMessageHistoryText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LobbyDatabase::createTableChatMessages()
|
void LobbyDatabase::createTableChatMessages()
|
||||||
@@ -69,9 +78,55 @@ void LobbyDatabase::insertChatMessage(const std::string & sender, const std::str
|
|||||||
insertChatMessageStatement->reset();
|
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)
|
void LobbyServer::onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message)
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
|
|
||||||
#include "../lib/network/NetworkServer.h"
|
#include "../lib/network/NetworkServer.h"
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
class JsonNode;
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
class SQLiteInstance;
|
class SQLiteInstance;
|
||||||
class SQLiteStatement;
|
class SQLiteStatement;
|
||||||
|
|
||||||
@@ -18,14 +22,23 @@ class LobbyDatabase
|
|||||||
{
|
{
|
||||||
std::unique_ptr<SQLiteInstance> database;
|
std::unique_ptr<SQLiteInstance> database;
|
||||||
std::unique_ptr<SQLiteStatement> insertChatMessageStatement;
|
std::unique_ptr<SQLiteStatement> insertChatMessageStatement;
|
||||||
|
std::unique_ptr<SQLiteStatement> getRecentMessageHistoryStatement;
|
||||||
|
|
||||||
void initializeDatabase();
|
void initializeDatabase();
|
||||||
void prepareStatements();
|
void prepareStatements();
|
||||||
void createTableChatMessages();
|
void createTableChatMessages();
|
||||||
public:
|
public:
|
||||||
|
struct ChatMessage
|
||||||
|
{
|
||||||
|
std::string sender;
|
||||||
|
std::string messageText;
|
||||||
|
int messageAgeSeconds;
|
||||||
|
};
|
||||||
|
|
||||||
LobbyDatabase();
|
LobbyDatabase();
|
||||||
|
|
||||||
void insertChatMessage(const std::string & sender, const std::string & messageText);
|
void insertChatMessage(const std::string & sender, const std::string & messageText);
|
||||||
|
std::vector<ChatMessage> getRecentMessageHistory();
|
||||||
};
|
};
|
||||||
|
|
||||||
class LobbyServer : public NetworkServer
|
class LobbyServer : public NetworkServer
|
||||||
@@ -34,6 +47,8 @@ class LobbyServer : public NetworkServer
|
|||||||
|
|
||||||
void onNewConnection(const std::shared_ptr<NetworkConnection> &) override;
|
void onNewConnection(const std::shared_ptr<NetworkConnection> &) override;
|
||||||
void onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message) 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:
|
public:
|
||||||
LobbyServer();
|
LobbyServer();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user