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

Implemented message receiving / broadcasting

This commit is contained in:
Ivan Savenko 2023-11-12 21:23:42 +02:00
parent 07fb313765
commit de5227142b
10 changed files with 108 additions and 39 deletions

View File

@ -17,6 +17,7 @@
#include "../windows/InfoWindows.h"
#include "../../lib/MetaString.h"
#include "../../lib/CConfigHandler.h"
LobbyClient::LobbyClient(LobbyWindow * window)
: window(window)
@ -24,6 +25,23 @@ LobbyClient::LobbyClient(LobbyWindow * window)
}
static std::string getCurrentTimeFormatted(int timeOffsetSeconds = 0)
{
// FIXME: better/unified way to format date
auto timeNowChrono = std::chrono::system_clock::now();
timeNowChrono += std::chrono::seconds(timeOffsetSeconds);
std::time_t timeNowC = std::chrono::system_clock::to_time_t(timeNowChrono);
std::tm timeNowTm = *std::localtime(&timeNowC);
MetaString timeFormatted;
timeFormatted.appendRawString("%d:%d");
timeFormatted.replaceNumber(timeNowTm.tm_hour);
timeFormatted.replaceNumber(timeNowTm.tm_min);
return timeFormatted.toString();
}
void LobbyClient::onPacketReceived(const std::vector<uint8_t> & message)
{
// FIXME: find better approach
@ -37,22 +55,27 @@ void LobbyClient::onPacketReceived(const std::vector<uint8_t> & message)
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());
std::string timeFormatted = getCurrentTimeFormatted(-ageSeconds);
window->onGameChatMessage(senderName, messageText, timeFormatted);
}
}
if (json["type"].String() == "chatMessage")
{
std::string senderName = json["senderName"].String();
std::string messageText = json["messageText"].String();
std::string timeFormatted = getCurrentTimeFormatted();
window->onGameChatMessage(senderName, messageText, timeFormatted);
}
}
void LobbyClient::onConnectionEstablished()
{
JsonNode toSend;
toSend["type"].String() = "authentication";
toSend["accountName"].String() = settings["general"]["playerName"].String();
sendMessage(toSend);
}
void LobbyClient::onConnectionFailed(const std::string & errorMessage)
@ -90,6 +113,11 @@ LobbyWidget::LobbyWidget(LobbyWindow * window)
build(config);
}
std::shared_ptr<CLabel> LobbyWidget::getAccountNameLabel()
{
return widget<CLabel>("accountNameLabel");
}
std::shared_ptr<CTextInput> LobbyWidget::getMessageInput()
{
return widget<CTextInput>("messageInput");
@ -110,6 +138,7 @@ LobbyWindow::LobbyWindow():
connection = std::make_shared<LobbyClient>(this);
connection->start("127.0.0.1", 30303);
widget->getAccountNameLabel()->setText(settings["general"]["playerName"].String());
addUsedEvents(TIME);
}

View File

@ -22,6 +22,7 @@ class LobbyWidget : public InterfaceObjectConfigurable
public:
LobbyWidget(LobbyWindow * window);
std::shared_ptr<CLabel> getAccountNameLabel();
std::shared_ptr<CTextInput> getMessageInput();
std::shared_ptr<CTextBox> getGameChat();
};
@ -32,6 +33,7 @@ class LobbyClient : public NetworkClient
void onPacketReceived(const std::vector<uint8_t> & message) override;
void onConnectionFailed(const std::string & errorMessage) override;
void onConnectionEstablished() override;
void onDisconnected() override;
public:

View File

@ -41,9 +41,9 @@
"rect": {"x": 5, "y": 5, "w": 250, "h": 40}
},
{
"name" : "accountNameLabel",
"type": "labelTitleMain",
"position": {"x": 15, "y": 10},
"text" : "Player Name"
"position": {"x": 15, "y": 10}
},
{
@ -91,8 +91,7 @@
"font": "small",
"alignment": "left",
"color": "white",
"text": "[00:00]{Player 1}: Hello\n[00:01]{Player 2}: HI!",
"rect": {"x": 430, "y": 70, "w": 430, "h": 495}
"rect": {"x": 440, "y": 70, "w": 430, "h": 495}
},
{

View File

@ -38,6 +38,8 @@ void NetworkClient::onConnected(const boost::system::error_code & ec)
connection = std::make_shared<NetworkConnection>(socket, *this);
connection->start();
onConnectionEstablished();
}
void NetworkClient::run()

View File

@ -30,6 +30,7 @@ class DLL_LINKAGE NetworkClient : boost::noncopyable, public INetworkConnectionL
protected:
virtual void onPacketReceived(const std::vector<uint8_t> & message) = 0;
virtual void onConnectionFailed(const std::string & errorMessage) = 0;
virtual void onConnectionEstablished() = 0;
virtual void onDisconnected() = 0;
void sendPacket(const std::vector<uint8_t> & message);

View File

@ -16,7 +16,7 @@ VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE NetworkConnection :public std::enable_shared_from_this<NetworkConnection>, boost::noncopyable
{
static const int messageHeaderSize = sizeof(uint32_t);
static const int messageMaxSize = 1024;
static const int messageMaxSize = 65536; // arbitrary size to prevent potential massive allocation if we receive garbage input
std::shared_ptr<NetworkSocket> socket;

View File

@ -56,6 +56,7 @@ void NetworkServer::onDisconnected(const std::shared_ptr<NetworkConnection> & co
{
assert(connections.count(connection));
connections.erase(connection);
onConnectionLost(connection);
}
VCMI_LIB_NAMESPACE_END

View File

@ -27,6 +27,7 @@ class DLL_LINKAGE NetworkServer : boost::noncopyable, public INetworkConnectionL
void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) override;
protected:
virtual void onNewConnection(const std::shared_ptr<NetworkConnection> &) = 0;
virtual void onConnectionLost(const std::shared_ptr<NetworkConnection> &) = 0;
void sendPacket(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message);

View File

@ -109,27 +109,14 @@ void LobbyServer::sendMessage(const std::shared_ptr<NetworkConnection> & target,
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::onConnectionLost(const std::shared_ptr<NetworkConnection> & connection)
{
activeAccounts.erase(connection);
}
void LobbyServer::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
{
// FIXME: find better approach
const char * payloadBegin = reinterpret_cast<const char*>(message.data());
@ -137,7 +124,46 @@ void LobbyServer::onPacketReceived(const std::shared_ptr<NetworkConnection> &, c
if (json["type"].String() == "sendChatMessage")
{
database->insertChatMessage("Unknown", json["messageText"].String());
if (activeAccounts.count(connection) == 0)
return; // unauthenticated
std::string senderName = activeAccounts[connection].accountName;
std::string messageText = json["messageText"].String();
database->insertChatMessage(senderName, messageText);
JsonNode reply;
reply["type"].String() = "chatMessage";
reply["messageText"].String() = messageText;
reply["senderName"].String() = senderName;
for (auto const & connection : activeAccounts)
sendMessage(connection.first, reply);
}
if (json["type"].String() == "authentication")
{
std::string accountName = json["accountName"].String();
activeAccounts[connection].accountName = accountName;
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);
}
}

View File

@ -43,9 +43,17 @@ public:
class LobbyServer : public NetworkServer
{
struct AccountState
{
std::string accountName;
};
std::map<std::shared_ptr<NetworkConnection>, AccountState> activeAccounts;
std::unique_ptr<LobbyDatabase> database;
void onNewConnection(const std::shared_ptr<NetworkConnection> &) override;
void onConnectionLost(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);