Browse Source

Implemented messages sending and storing in database

Ivan Savenko 1 year ago
parent
commit
f10b6df989

+ 43 - 3
client/serverLobby/LobbyWindow.cpp

@@ -13,9 +13,16 @@
 
 
 #include "../gui/CGuiHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/WindowHandler.h"
 #include "../gui/WindowHandler.h"
+#include "../widgets/TextControls.h"
 
 
 #include "../windows/InfoWindows.h"
 #include "../windows/InfoWindows.h"
 
 
+LobbyClient::LobbyClient(LobbyWindow * window)
+	: window(window)
+{
+
+}
+
 void LobbyClient::onPacketReceived(const std::vector<uint8_t> & message)
 void LobbyClient::onPacketReceived(const std::vector<uint8_t> & message)
 {
 {
 
 
@@ -33,22 +40,42 @@ void LobbyClient::onDisconnected()
 	CInfoWindow::showInfoDialog("Connection to game lobby was lost!", {});
 	CInfoWindow::showInfoDialog("Connection to game lobby was lost!", {});
 }
 }
 
 
-LobbyWidget::LobbyWidget()
+void LobbyClient::sendMessage(const JsonNode & data)
+{
+	std::string payloadString = data.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(payloadBuffer);
+}
+
+LobbyWidget::LobbyWidget(LobbyWindow * window)
+	: window(window)
 {
 {
 	addCallback("closeWindow", [](int) { GH.windows().popWindows(1); });
 	addCallback("closeWindow", [](int) { GH.windows().popWindows(1); });
+	addCallback("sendMessage", [this](int) { this->window->doSendChatMessage(); });
 
 
 	const JsonNode config(JsonPath::builtin("config/widgets/lobbyWindow.json"));
 	const JsonNode config(JsonPath::builtin("config/widgets/lobbyWindow.json"));
 	build(config);
 	build(config);
 }
 }
 
 
+std::shared_ptr<CTextInput> LobbyWidget::getMessageInput()
+{
+	return widget<CTextInput>("messageInput");
+}
+
 LobbyWindow::LobbyWindow():
 LobbyWindow::LobbyWindow():
 	CWindowObject(BORDERED)
 	CWindowObject(BORDERED)
 {
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
-	widget = std::make_shared<LobbyWidget>();
+	widget = std::make_shared<LobbyWidget>(this);
 	pos = widget->pos;
 	pos = widget->pos;
 	center();
 	center();
-	connection = std::make_shared<LobbyClient>();
+	connection = std::make_shared<LobbyClient>(this);
 
 
 	connection->start("127.0.0.1", 30303);
 	connection->start("127.0.0.1", 30303);
 
 
@@ -59,3 +86,16 @@ void LobbyWindow::tick(uint32_t msPassed)
 {
 {
 	connection->poll();
 	connection->poll();
 }
 }
+
+void LobbyWindow::doSendChatMessage()
+{
+	std::string messageText = widget->getMessageInput()->getText();
+
+	JsonNode toSend;
+	toSend["type"].String() = "sendChatMessage";
+	toSend["messageText"].String() = messageText;
+
+	connection->sendMessage(toSend);
+
+	widget->getMessageInput()->setText("");
+}

+ 16 - 2
client/serverLobby/LobbyWindow.h

@@ -14,19 +14,29 @@
 
 
 #include "../../lib/network/NetworkClient.h"
 #include "../../lib/network/NetworkClient.h"
 
 
+class LobbyWindow;
+
 class LobbyWidget : public InterfaceObjectConfigurable
 class LobbyWidget : public InterfaceObjectConfigurable
 {
 {
+	LobbyWindow * window;
 public:
 public:
-	LobbyWidget();
+	LobbyWidget(LobbyWindow * window);
+
+	std::shared_ptr<CTextInput> getMessageInput();
 };
 };
 
 
 class LobbyClient : public NetworkClient
 class LobbyClient : public NetworkClient
 {
 {
+	LobbyWindow * window;
+
 	void onPacketReceived(const std::vector<uint8_t> & message) override;
 	void onPacketReceived(const std::vector<uint8_t> & message) override;
 	void onConnectionFailed(const std::string & errorMessage) override;
 	void onConnectionFailed(const std::string & errorMessage) override;
 	void onDisconnected() override;
 	void onDisconnected() override;
+
 public:
 public:
-	LobbyClient() = default;
+	explicit LobbyClient(LobbyWindow * window);
+
+	void sendMessage(const JsonNode & data);
 };
 };
 
 
 class LobbyWindow : public CWindowObject
 class LobbyWindow : public CWindowObject
@@ -38,4 +48,8 @@ class LobbyWindow : public CWindowObject
 
 
 public:
 public:
 	LobbyWindow();
 	LobbyWindow();
+
+	void doSendChatMessage();
+
+	void onGameChatMessage(std::string sender, std::string message, std::string when);
 };
 };

+ 16 - 10
config/widgets/lobbyWindow.json

@@ -85,15 +85,25 @@
 			"position": {"x": 440, "y": 53},
 			"position": {"x": 440, "y": 53},
 			"text" : "Game Chat"
 			"text" : "Game Chat"
 		},
 		},
+		{
+			"type": "textBox",
+			"name": "gameChat",
+			"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}
+		},
 		
 		
 		{
 		{
 			"type": "areaFilled",
 			"type": "areaFilled",
 			"rect": {"x": 430, "y": 565, "w": 395, "h": 25}
 			"rect": {"x": 430, "y": 565, "w": 395, "h": 25}
 		},
 		},
 		{
 		{
-			"type": "labelTitle",
-			"position": {"x": 440, "y": 568},
-			"text" : "Enter Message"
+			"name" : "messageInput",
+			"type": "textInput",
+			"alignment" : "left",
+			"rect": {"x": 440, "y": 568, "w": 375, "h": 20}
 		},
 		},
 		
 		
 		{
 		{
@@ -112,7 +122,7 @@
 			"image": "settingsWindow/button80",
 			"image": "settingsWindow/button80",
 			"help": "core.help.288",
 			"help": "core.help.288",
 			"callback": "closeWindow",
 			"callback": "closeWindow",
-			"hotkey": "globalReturn",
+			"hotkey": "globalCancel",
 			"items":
 			"items":
 			[
 			[
 				{
 				{
@@ -130,8 +140,8 @@
 			"position": {"x": 828, "y": 565},
 			"position": {"x": 828, "y": 565},
 			"image": "settingsWindow/button32",
 			"image": "settingsWindow/button32",
 			"help": "core.help.288",
 			"help": "core.help.288",
-			"callback": "closeWindow",
-			"hotkey": "globalReturn",
+			"callback": "sendMessage",
+			"hotkey": "globalAccept",
 			"items":
 			"items":
 			[
 			[
 				{
 				{
@@ -149,8 +159,6 @@
 			"position": {"x": 10, "y": 520},
 			"position": {"x": 10, "y": 520},
 			"image": "settingsWindow/button190",
 			"image": "settingsWindow/button190",
 			"help": "core.help.288",
 			"help": "core.help.288",
-			"callback": "closeWindow",
-			"hotkey": "globalReturn",
 			"items":
 			"items":
 			[
 			[
 				{
 				{
@@ -168,8 +176,6 @@
 			"position": {"x": 10, "y": 555},
 			"position": {"x": 10, "y": 555},
 			"image": "settingsWindow/button190",
 			"image": "settingsWindow/button190",
 			"help": "core.help.288",
 			"help": "core.help.288",
-			"callback": "closeWindow",
-			"hotkey": "globalReturn",
 			"items":
 			"items":
 			[
 			[
 				{
 				{

+ 1 - 1
lib/network/NetworkClient.h

@@ -32,12 +32,12 @@ protected:
 	virtual void onConnectionFailed(const std::string & errorMessage) = 0;
 	virtual void onConnectionFailed(const std::string & errorMessage) = 0;
 	virtual void onDisconnected() = 0;
 	virtual void onDisconnected() = 0;
 
 
+	void sendPacket(const std::vector<uint8_t> & message);
 public:
 public:
 	NetworkClient();
 	NetworkClient();
 	virtual ~NetworkClient() = default;
 	virtual ~NetworkClient() = default;
 
 
 	void start(const std::string & host, uint16_t port);
 	void start(const std::string & host, uint16_t port);
-	void sendPacket(const std::vector<uint8_t> & message);
 	void run();
 	void run();
 	void poll();
 	void poll();
 };
 };

+ 1 - 1
lib/network/NetworkConnection.cpp

@@ -77,7 +77,7 @@ void NetworkConnection::onPacketReceived(const boost::system::error_code & ec, u
 
 
 	message.resize(expectedPacketSize);
 	message.resize(expectedPacketSize);
 	std::istream istream(&readBuffer);
 	std::istream istream(&readBuffer);
-	istream.read(reinterpret_cast<char *>(message.data()), messageHeaderSize);
+	istream.read(reinterpret_cast<char *>(message.data()), expectedPacketSize);
 
 
 	listener.onPacketReceived(shared_from_this(), message);
 	listener.onPacketReceived(shared_from_this(), message);
 
 

+ 57 - 1
lobby/LobbyServer.cpp

@@ -12,6 +12,8 @@
 
 
 #include "SQLiteConnection.h"
 #include "SQLiteConnection.h"
 
 
+#include "../lib/JsonNode.h"
+
 #include <boost/uuid/uuid_generators.hpp>
 #include <boost/uuid/uuid_generators.hpp>
 #include <boost/uuid/uuid_io.hpp>
 #include <boost/uuid/uuid_io.hpp>
 
 
@@ -20,6 +22,53 @@ static const int LISTENING_PORT = 30303;
 //static const std::string SERVER_NAME = GameConstants::VCMI_VERSION + " (server)";
 //static const std::string SERVER_NAME = GameConstants::VCMI_VERSION + " (server)";
 //static const std::string SERVER_UUID = boost::uuids::to_string(boost::uuids::random_generator()());
 //static const std::string SERVER_UUID = boost::uuids::to_string(boost::uuids::random_generator()());
 
 
+void LobbyDatabase::prepareStatements()
+{
+	static const std::string insertChatMessageText = R"(
+		INSERT INTO chatMessages(senderName, messageText) VALUES( ?, ?);
+	)";
+
+	insertChatMessageStatement = database->prepare(insertChatMessageText);
+}
+
+void LobbyDatabase::createTableChatMessages()
+{
+	static const std::string statementText = R"(
+		CREATE TABLE IF NOT EXISTS chatMessages (
+			id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+			senderName TEXT,
+			messageText TEXT,
+			sendTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
+		);
+	)";
+
+	auto statement = database->prepare(statementText);
+	statement->execute();
+}
+
+void LobbyDatabase::initializeDatabase()
+{
+	createTableChatMessages();
+}
+
+LobbyDatabase::LobbyDatabase()
+{
+	database = SQLiteInstance::open(DATABASE_PATH, true);
+
+	if (!database)
+		throw std::runtime_error("Failed to open SQLite database!");
+
+	initializeDatabase();
+	prepareStatements();
+}
+
+void LobbyDatabase::insertChatMessage(const std::string & sender, const std::string & messageText)
+{
+	insertChatMessageStatement->setBinds(sender, messageText);
+	insertChatMessageStatement->execute();
+	insertChatMessageStatement->reset();
+}
+
 void LobbyServer::onNewConnection(const std::shared_ptr<NetworkConnection> &)
 void LobbyServer::onNewConnection(const std::shared_ptr<NetworkConnection> &)
 {
 {
 
 
@@ -27,12 +76,19 @@ void LobbyServer::onNewConnection(const std::shared_ptr<NetworkConnection> &)
 
 
 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)
 {
 {
+	// FIXME: find better approach
+	const char * payloadBegin = reinterpret_cast<const char*>(message.data());
+	JsonNode json(payloadBegin, message.size());
 
 
+	if (json["type"].String() == "sendChatMessage")
+	{
+		database->insertChatMessage("Unknown", json["messageText"].String());
+	}
 }
 }
 
 
 LobbyServer::LobbyServer()
 LobbyServer::LobbyServer()
+	: database(new LobbyDatabase())
 {
 {
-	database = SQLiteInstance::open(DATABASE_PATH, true);
 }
 }
 
 
 int main(int argc, const char * argv[])
 int main(int argc, const char * argv[])

+ 16 - 1
lobby/LobbyServer.h

@@ -12,10 +12,25 @@
 #include "../lib/network/NetworkServer.h"
 #include "../lib/network/NetworkServer.h"
 
 
 class SQLiteInstance;
 class SQLiteInstance;
+class SQLiteStatement;
 
 
-class LobbyServer : public NetworkServer
+class LobbyDatabase
 {
 {
 	std::unique_ptr<SQLiteInstance> database;
 	std::unique_ptr<SQLiteInstance> database;
+	std::unique_ptr<SQLiteStatement> insertChatMessageStatement;
+
+	void initializeDatabase();
+	void prepareStatements();
+	void createTableChatMessages();
+public:
+	LobbyDatabase();
+
+	void insertChatMessage(const std::string & sender, const std::string & messageText);
+};
+
+class LobbyServer : public NetworkServer
+{
+	std::unique_ptr<LobbyDatabase> database;
 
 
 	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;

+ 2 - 1
lobby/SQLiteConnection.cpp

@@ -16,7 +16,8 @@ static void on_sqlite_error( sqlite3 * connection, [[maybe_unused]] int result )
 {
 {
 	if ( result != SQLITE_OK )
 	if ( result != SQLITE_OK )
 	{
 	{
-		printf( "sqlite error: %s\n", sqlite3_errmsg( connection ) );
+		const char * message = sqlite3_errmsg( connection );
+		printf( "sqlite error: %s\n", message );
 	}
 	}
 
 
 	assert( result == SQLITE_OK );
 	assert( result == SQLITE_OK );