From 0469c43a45310b6b92eb704773e3a34beb57f288 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 1 Nov 2018 07:17:49 +0100 Subject: Move room code to dchat_core, add ability to send messages --- depends/dchat_core | 2 +- include/ChannelDataType.hpp | 16 ------ include/ChatMessage.hpp | 3 +- include/ChatWindow.hpp | 26 ++++------ include/LoginWindow.hpp | 2 +- include/User.hpp | 13 ----- include/Window.hpp | 4 +- src/ChatMessage.cpp | 5 +- src/ChatWindow.cpp | 121 ++++++++++++++++++++++---------------------- src/Window.cpp | 107 ++++++++++++++++----------------------- 10 files changed, 124 insertions(+), 175 deletions(-) delete mode 100644 include/ChannelDataType.hpp delete mode 100644 include/User.hpp diff --git a/depends/dchat_core b/depends/dchat_core index 699811d..391e0cb 160000 --- a/depends/dchat_core +++ b/depends/dchat_core @@ -1 +1 @@ -Subproject commit 699811dbcc8194c95ffe7874ac8d2fb97e039410 +Subproject commit 391e0cb6a667fa384d61a9ef7909482d2e1bbb50 diff --git a/include/ChannelDataType.hpp b/include/ChannelDataType.hpp deleted file mode 100644 index 21e828d..0000000 --- a/include/ChannelDataType.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -namespace dchat -{ - enum class ChannelDataType : u8 - { - ADD_MESSAGE, - EDIT_MESSAGE, - DELETE_MESSAGE, - NICKNAME_CHANGE, - CHANGE_AVATAR, - CHANGE_CHANNEL_NAME, - }; -} \ No newline at end of file diff --git a/include/ChatMessage.hpp b/include/ChatMessage.hpp index c13db9d..c1ef459 100644 --- a/include/ChatMessage.hpp +++ b/include/ChatMessage.hpp @@ -10,13 +10,12 @@ namespace dchat class ChatMessage : public Gtk::Grid { public: - ChatMessage(const Glib::ustring &username, const Glib::ustring &text, uint32_t timestampSeconds, const User *user); + ChatMessage(const Glib::ustring &username, const Glib::ustring &text, uint32_t timestampSeconds); Gtk::Grid avatar; Gtk::Label username; Gtk::Label text; uint32_t timestampSeconds; - const User *user; private: bool updateContent(const Cairo::RefPtr &cairo); }; diff --git a/include/ChatWindow.hpp b/include/ChatWindow.hpp index 0b58506..988b225 100644 --- a/include/ChatWindow.hpp +++ b/include/ChatWindow.hpp @@ -1,6 +1,6 @@ #pragma once -#include "User.hpp" +#include #include #include #include @@ -20,13 +20,11 @@ namespace dchat { public: ChatWindow(); - void addChannel(const odhtdb::Hash &nodeHash); - void addLocalMessage(const odhtdb::Hash &channelId, const odhtdb::Signature::PublicKey &userPublicKey, uint32_t timestampSeconds, Glib::ustring msg); - void addUser(const odhtdb::Signature::PublicKey &userPublicKey); - void setUserNickname(const odhtdb::Signature::PublicKey &userPublicKey, const Glib::ustring &name); - - // Returns nullptr if user with @publicKey is not found - User* getUserByPublicKey(const odhtdb::Signature::PublicKey &publicKey) const; + void addRoom(std::shared_ptr room); + void addMessage(const RoomAddMessageRequest &request); + void addUser(std::shared_ptr room, std::shared_ptr user); + void setUserNickname(const UserChangeNicknameRequest &request); + void scrollToBottom(); private: void setupTopBar(); void setupLeftPanel(Gtk::Paned *sidePanels); @@ -42,17 +40,15 @@ namespace dchat Gtk::Grid messageAreaLayout; Gtk::TextView chatInput; - struct ChannelData + struct RoomData { Gtk::ToggleButton *button; - int messageCount; }; - odhtdb::MapHash channelDataById; - int channelCount; - std::vector users; - - ChatMessage *lastMessage; + odhtdb::MapHash roomDataById; + odhtdb::MapHash messageById; int chatPrevNumLines; + int roomCount; + std::shared_ptr currentRoom; }; } \ No newline at end of file diff --git a/include/LoginWindow.hpp b/include/LoginWindow.hpp index ea9b905..d5585a5 100644 --- a/include/LoginWindow.hpp +++ b/include/LoginWindow.hpp @@ -22,7 +22,7 @@ namespace dchat private: void setupLogin(); void setupRegister(); - private: + public: Gtk::Grid loginLayout; Gtk::Entry loginUsernameInput; Gtk::Entry loginPasswordInput; diff --git a/include/User.hpp b/include/User.hpp deleted file mode 100644 index 471a5cc..0000000 --- a/include/User.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include - -namespace dchat -{ - struct User - { - const odhtdb::Signature::PublicKey publicKey; - Glib::ustring name; - }; -} \ No newline at end of file diff --git a/include/Window.hpp b/include/Window.hpp index 4c67a68..a29ec62 100644 --- a/include/Window.hpp +++ b/include/Window.hpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,7 +26,7 @@ namespace dchat void draw(const Cairo::RefPtr &cairo) { Gtk::Overlay::draw(cairo); } }; - std::unique_ptr database; + std::shared_ptr rooms; std::mutex databaseCallbackMutex; OverlayDrawable overlay; Gtk::Stack stack; diff --git a/src/ChatMessage.cpp b/src/ChatMessage.cpp index 93b52e9..d48a6a9 100644 --- a/src/ChatMessage.cpp +++ b/src/ChatMessage.cpp @@ -4,11 +4,10 @@ namespace dchat { - ChatMessage::ChatMessage(const Glib::ustring &_username, const Glib::ustring &_text, uint32_t _timestampSeconds, const User *_user) : + ChatMessage::ChatMessage(const Glib::ustring &_username, const Glib::ustring &_text, uint32_t _timestampSeconds) : username(_username), text(_text), - timestampSeconds(_timestampSeconds), - user(_user) + timestampSeconds(_timestampSeconds) { avatar.set_halign(Gtk::ALIGN_START); avatar.set_valign(Gtk::ALIGN_START); diff --git a/src/ChatWindow.cpp b/src/ChatWindow.cpp index 041d2c3..98c4269 100644 --- a/src/ChatWindow.cpp +++ b/src/ChatWindow.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace dchat @@ -11,8 +12,7 @@ namespace dchat const int MERGE_MESSAGE_TIMESTAMP_DIFF_SEC = 60; ChatWindow::ChatWindow() : - channelCount(0), - lastMessage(nullptr) + roomCount(0) { setupTopBar(); @@ -107,9 +107,20 @@ namespace dchat chatInput.set_hexpand(true); chatInput.set_name("chat-input"); chatInput.set_wrap_mode(Gtk::WrapMode::WRAP_WORD_CHAR); + chatScrollWindow->add(chatInput); double fontSize = 18.5;//PANGO_PIXELS(chatInput.get_style_context()->get_font().get_size()); chatPrevNumLines = 1; + chatInput.signal_key_press_event().connect([this](GdkEventKey *event) + { + if((event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter) && !(event->state & Gdk::SHIFT_MASK)) + { + currentRoom->publishMessage(chatInput.get_buffer()->get_text()); + chatInput.get_buffer()->set_text(""); + return true; + } + return false; + }, false); chatInput.get_buffer()->signal_changed().connect([this, chatScrollWindow, fontSize] { int numLines = chatInput.get_buffer()->get_line_count(); @@ -144,100 +155,90 @@ namespace dchat chatScrollWindow->set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_ALWAYS); } }); - chatScrollWindow->add(chatInput); } - void ChatWindow::addChannel(const odhtdb::Hash &nodeHash) + void ChatWindow::addRoom(std::shared_ptr room) { - assert(channelDataById.find(nodeHash) == channelDataById.end()); - fprintf(stderr, "Added channel %s\n", nodeHash.toString().c_str()); + fprintf(stderr, "Added channel %s\n", room->id->toString().c_str()); Gtk::ToggleButton *channelButton = Gtk::manage(new Gtk::ToggleButton("Channel name")); channelButton->set_active(true); channelButton->get_style_context()->add_class("channel-button"); channelButton->set_hexpand(true); channelButton->get_child()->set_halign(Gtk::ALIGN_START); channelButton->show(); - leftPanelChannels.attach(*channelButton, 0, 1 + channelCount, 1, 1); - ++channelCount; - channelDataById[nodeHash] = { channelButton, 0 }; + leftPanelChannels.attach(*channelButton, 0, 1 + roomCount, 1, 1); + ++roomCount; + roomDataById[*room->id] = { channelButton }; + currentRoom = room; } - void ChatWindow::addLocalMessage(const odhtdb::Hash &channelId, const odhtdb::Signature::PublicKey &userPublicKey, uint32_t timestampSeconds, Glib::ustring msg) + void ChatWindow::addMessage(const RoomAddMessageRequest &request) { - auto it = channelDataById.find(channelId); - assert(it != channelDataById.end()); - User *user = getUserByPublicKey(userPublicKey); - if(!user) - { - fprintf(stderr, "Unable to add message to channel because the user %s doesn't exist in it\n", userPublicKey.toString().c_str()); - return; - } + auto roomMessages = request.room->messages; + RoomMessage *lastMessage = nullptr; + if(!roomMessages.empty()) + lastMessage = &roomMessages.back(); - if(lastMessage && lastMessage->user->publicKey == userPublicKey) + if(lastMessage && lastMessage->creator->publicKey == request.message.creator->publicKey) { - int64_t msgTimeDiff = (int64_t)timestampSeconds - (int64_t)lastMessage->timestampSeconds; + int64_t msgTimeDiff = (int64_t)request.message.timestampSeconds - (int64_t)lastMessage->timestampSeconds; if(msgTimeDiff <= MERGE_MESSAGE_TIMESTAMP_DIFF_SEC) { - lastMessage->text.set_text(lastMessage->text.get_text() + "\n" + msg); + auto message = messageById[lastMessage->id]; + message->text.set_text(message->text.get_text() + "\n" + request.message.text); + // Since messages that are sent withing a timeframe are combined, several message ids can refer to the same message + messageById[request.message.id] = message; + if(*request.room->id == *currentRoom->id) + { + auto adj = messageArea.get_vadjustment(); + adj->set_value(adj->get_upper()); + messageAreaLayout.queue_draw(); + while(gtk_events_pending()) + gtk_main_iteration_do(FALSE); + } return; } } - ChatMessage *message = Gtk::manage(new ChatMessage(user->name, msg, timestampSeconds, user)); - lastMessage = message; + ChatMessage *message = Gtk::manage(new ChatMessage(request.message.creator->nickname, request.message.text, request.message.timestampSeconds)); message->set_valign(Gtk::Align::ALIGN_START); message->set_hexpand(true); message->show_all(); - messageAreaLayout.attach(*message, 0, it->second.messageCount, 1, 1); - ++it->second.messageCount; - } + messageById[request.message.id] = message; + messageAreaLayout.attach(*message, 0, roomMessages.size(), 1, 1); - void ChatWindow::addUser(const odhtdb::Signature::PublicKey &userPublicKey) - { - User *existingUser = getUserByPublicKey(userPublicKey); - if(existingUser) + // TODO: When we get a message in the current room we scroll to the bottom, but this should only be done if we are not manually scrolling to view old messages + if(*request.room->id == *currentRoom->id) { - fprintf(stderr, "ChatWindow::addUser: user %s was not added because the user has already been added\n", userPublicKey.toString().c_str()); - return; + auto adj = messageArea.get_vadjustment(); + adj->set_value(adj->get_upper()); + messageAreaLayout.queue_draw(); + while(gtk_events_pending()) + gtk_main_iteration_do(FALSE); } + } + void ChatWindow::addUser(std::shared_ptr room, std::shared_ptr user) + { Gtk::Label *username = Gtk::manage(new Gtk::Label("NoName")); username->set_halign(Gtk::ALIGN_START); username->show(); username->get_style_context()->add_class("username-list-username"); - leftPanelUsers.attach(*username, 0, 1 + users.size(), 1, 1); - users.push_back(new User { userPublicKey, "NoName" }); - fprintf(stderr, "Added user %s\n", userPublicKey.toString().c_str()); + user->userdata = username; + leftPanelUsers.attach(*username, 0, room->userByPublicKey.size(), 1, 1); + fprintf(stderr, "Added user %s\n", user->publicKey.toString().c_str()); } - void ChatWindow::setUserNickname(const odhtdb::Signature::PublicKey &userPublicKey, const Glib::ustring &name) + void ChatWindow::setUserNickname(const UserChangeNicknameRequest &request) { - for(size_t i = 0; i < users.size(); ++i) - { - User *user = users[i]; - if(user->publicKey == userPublicKey) - { - user->name = name; - Gtk::Widget *usernameLabel = leftPanelUsers.get_child_at(0, 1 + i); - assert(usernameLabel); - //assert(usernameLabel->get_type() == Gtk::Label::get_type()); - static_cast(usernameLabel)->set_text(name); - fprintf(stderr, "Set nickname for user %s to %s\n", userPublicKey.toString().c_str(), name.c_str()); - return; - } - } - fprintf(stderr, "ChatWindow::setUserNickname: user %s doesn't exist\n", userPublicKey.toString().c_str()); + Gtk::Label *userNicknameLabel = (Gtk::Label*)request.user->userdata; + userNicknameLabel->set_text(request.newNickname); + fprintf(stderr, "Set nickname for user %s to %s\n", request.user->publicKey.toString().c_str(), request.newNickname.c_str()); } - User* ChatWindow::getUserByPublicKey(const odhtdb::Signature::PublicKey &publicKey) const + void ChatWindow::scrollToBottom() { - for(User *user : users) - { - if(user->publicKey == publicKey) - { - return user; - } - } - return nullptr; + auto adj = messageArea.get_vadjustment(); + adj->set_value(adj->get_upper()); } } \ No newline at end of file diff --git a/src/Window.cpp b/src/Window.cpp index 6a0ab64..b9e1490 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -1,15 +1,16 @@ #include "../include/Window.hpp" -#include "../include/ChannelDataType.hpp" +#include #include "../include/WindowNotification.hpp" #include #include #include #include +#include namespace dchat { - const int nodesPerColumn = 5; - const int nodesPerRow = 5; + const int nodesPerColumn = 10; + const int nodesPerRow = 10; Window::Window() { @@ -28,12 +29,12 @@ namespace dchat overlay.show(); windowNotification->show_all(); stack.show(); - chatWindow.show_all(); - loginWindow.show(); + //chatWindow.show_all(); + //loginWindow.show(); loginWindow.setLoginHandler([this, windowNotification](const Glib::ustring &username, const Glib::ustring &password) { - if(!database) + if(!rooms || !rooms->database) { windowNotification->show("You are not connected to the bootstrap node yet! please wait..."); return; @@ -42,15 +43,18 @@ namespace dchat try { fprintf(stderr, "Trying to login with username %s\n", username.raw().c_str()); - auto storedNodes = database->getStoredNodeUserInfoDecrypted(username.raw(), password.raw()); + rooms->loginUser(username.raw(), password.raw()); windowNotification->show(Glib::ustring("Successfully logged in as ") + username); drawBackgroundConnection.disconnect(); + chatWindow.show_all(); stack.set_visible_child(chatWindow); - for(auto &nodeInfo : storedNodes) + Glib::signal_timeout().connect([this] { - database->loadNode(nodeInfo.first); - } + printf("scroll to bottom!\n"); + chatWindow.scrollToBottom(); + return false; + }, 100); } catch(std::exception &e) { @@ -62,7 +66,7 @@ namespace dchat loginWindow.setRegisterHandler([this, windowNotification](const Glib::ustring &username, const Glib::ustring &password) { - if(!database) + if(!rooms || !rooms->database) { windowNotification->show("You are not connected to the bootstrap node yet! please wait..."); return; @@ -71,9 +75,10 @@ namespace dchat try { fprintf(stderr, "Trying to register username %s\n", username.raw().c_str()); - database->storeUserWithoutNodes(username.raw(), password.raw()); + rooms->registerUser(username.raw(), password.raw()); windowNotification->show(Glib::ustring("Successfully registered user ") + username); drawBackgroundConnection.disconnect(); + chatWindow.show_all(); stack.set_visible_child(chatWindow); } catch(std::exception &e) @@ -91,65 +96,43 @@ namespace dchat windowNotification->show("Passwords do not match"); }); - odhtdb::DatabaseCallbackFuncs callbackFuncs; - callbackFuncs.createNodeCallbackFunc = [this](const odhtdb::DatabaseCreateNodeRequest &request) + RoomCallbackFuncs roomCallbackFuncs; + roomCallbackFuncs.connectCallbackFunc = [this, windowNotification](std::shared_ptr rooms, const char *errMsg) { - std::lock_guard lock(databaseCallbackMutex); - chatWindow.addChannel(*request.nodeHash); - chatWindow.addUser(*request.creatorPublicKey); - }; - - callbackFuncs.addNodeCallbackFunc = [this](const odhtdb::DatabaseAddNodeRequest &request) - { - std::lock_guard lock(databaseCallbackMutex); - if(request.decryptedData.size == 0) - return; - - ChannelDataType channelDataType = (ChannelDataType)static_cast(request.decryptedData.data)[0]; - try + this->rooms = rooms; + if(rooms) { - switch(channelDataType) - { - case ChannelDataType::ADD_MESSAGE: - { - Glib::ustring msg((const char*)request.decryptedData.data + 1, request.decryptedData.size - 1); - uint32_t timestampSeconds = ntp::NtpTimestamp::fromCombined(request.timestamp).seconds; - chatWindow.addLocalMessage(*request.nodeHash, *request.creatorPublicKey, timestampSeconds, std::move(msg)); - break; - } - case ChannelDataType::NICKNAME_CHANGE: - { - sibs::SafeDeserializer deserializer((const u8*)request.decryptedData.data + 1, request.decryptedData.size - 1); - u8 nameLength = deserializer.extract(); - if(nameLength > 0) - { - std::string nickname; - nickname.resize(nameLength); - deserializer.extract((u8*)&nickname[0], nameLength); - chatWindow.setUserNickname(*request.creatorPublicKey, nickname); - } - break; - } - default: - break; - } + loginWindow.show(); + stack.set_visible_child(loginWindow); + windowNotification->show("Connected to 83.252.53.188:27130"); + loginWindow.loginUsernameInput.grab_focus(); } - catch(std::exception &e) + else { - fprintf(stderr, "Failed to process add node request, reason: %s\n", e.what()); + std::string errMsgToShow = "Failed to connect to boostrap node, reason: "; + errMsgToShow += errMsg; + windowNotification->show(errMsgToShow); } }; - - callbackFuncs.addUserCallbackFunc = [this](const odhtdb::DatabaseAddUserRequest &request) + roomCallbackFuncs.createRoomCallbackFunc = [this](std::shared_ptr room) + { + chatWindow.addRoom(room); + }; + roomCallbackFuncs.addUserCallbackFunc = [this](std::shared_ptr room, std::shared_ptr user) + { + chatWindow.addUser(room, user); + }; + roomCallbackFuncs.addMessageCallbackFunc = [this](const RoomAddMessageRequest &request) + { + chatWindow.addMessage(request); + }; + roomCallbackFuncs.userChangeNicknameCallbackFunc = [this](const UserChangeNicknameRequest &request) { - std::lock_guard lock(databaseCallbackMutex); - chatWindow.addUser(*request.userToAddPublicKey); + chatWindow.setUserNickname(request); }; - fprintf(stderr, "Connecting...\n"); - database = odhtdb::Database::connect("83.252.53.188", 27130, Cache::getDchatDir(), callbackFuncs).get(); - stack.set_visible_child(loginWindow); - windowNotification->show("Connected to 83.252.53.188:27130"); + windowNotification->show("Connecting to 83.252.53.188:27130"); + Rooms::connect("83.252.53.188", 27130, roomCallbackFuncs); backgroundRng.seed(std::random_device()()); std::uniform_int_distribution sizeDeviationRand(0, 5); -- cgit v1.2.3