diff --git a/libs/ChatSection/include/Status/ChatSection/ChatSectionController.h b/libs/ChatSection/include/Status/ChatSection/ChatSectionController.h index d02b587639..b63c991aa4 100644 --- a/libs/ChatSection/include/Status/ChatSection/ChatSectionController.h +++ b/libs/ChatSection/include/Status/ChatSection/ChatSectionController.h @@ -24,6 +24,7 @@ public: Q_INVOKABLE void init(const QString& sectionId); Q_INVOKABLE void setCurrentChatIndex(int index); + Q_INVOKABLE void sendMessage(const QString &message) const; signals: void chatsModelChanged(); diff --git a/libs/ChatSection/qml/Status/ChatSection/ContentView.qml b/libs/ChatSection/qml/Status/ChatSection/ContentView.qml index 6871702c99..43c01efe2e 100644 --- a/libs/ChatSection/qml/Status/ChatSection/ContentView.qml +++ b/libs/ChatSection/qml/Status/ChatSection/ContentView.qml @@ -8,6 +8,7 @@ Item { id: root required property var selectedChat + required property var chatSectionController ColumnLayout { anchors.left: parent.left @@ -37,5 +38,18 @@ Item { Label { text: "is muted: %1".arg(root.selectedChat.muted) } + + Row { + TextField { + id: chatInput + width: root.width / 2 + } + + Button { + id: sendMessageButton + text: "Send" + onClicked: chatSectionController.sendMessage(chatInput.text) + } + } } } diff --git a/libs/ChatSection/qml/Status/ChatSection/MainView.qml b/libs/ChatSection/qml/Status/ChatSection/MainView.qml index 3fd5a0601a..a0a4d7b4fc 100644 --- a/libs/ChatSection/qml/Status/ChatSection/MainView.qml +++ b/libs/ChatSection/qml/Status/ChatSection/MainView.qml @@ -46,6 +46,7 @@ PanelAndContentBase { Layout.fillHeight: true selectedChat: chatSectionController.currentChat + chatSectionController: chatSectionController } } } diff --git a/libs/ChatSection/src/ChatSectionController.cpp b/libs/ChatSection/src/ChatSectionController.cpp index ac07cbf322..76725a31d3 100644 --- a/libs/ChatSection/src/ChatSectionController.cpp +++ b/libs/ChatSection/src/ChatSectionController.cpp @@ -1,5 +1,9 @@ #include "Status/ChatSection/ChatSectionController.h" +#include +#include +#include + using namespace Status::ChatSection; ChatSectionController::ChatSectionController() @@ -39,3 +43,18 @@ void ChatSectionController::setCurrentChatIndex(int index) m_currentChat = chat; emit currentChatChanged(); } + +void ChatSectionController::sendMessage(const QString &message) const +{ + namespace Messages = StatusGo::Messages; + auto chatMessage = Messages::InputMessage::createTextMessage(message, m_currentChat->id()); + try { + Messages::sendMessage(chatMessage); + } + catch(const StatusGo::CallPrivateRpcError& rpcError) + { + qWarning() << "Can't send message " << message + << " to id " << m_currentChat->id() + << ", error: " << rpcError.errorResponse().error.message.c_str(); + } +} diff --git a/libs/StatusGoQt/CMakeLists.txt b/libs/StatusGoQt/CMakeLists.txt index cd03eaae12..b0f0ef3494 100644 --- a/libs/StatusGoQt/CMakeLists.txt +++ b/libs/StatusGoQt/CMakeLists.txt @@ -106,6 +106,12 @@ target_sources(${PROJECT_NAME} src/StatusGo/Chat/ChatDto.h src/StatusGo/Chat/ChatDto.cpp + src/StatusGo/Messages/InputMessage.h + src/StatusGo/Messages/InputMessage.cpp + src/StatusGo/Messages/MessagesApi.h + src/StatusGo/Messages/MessagesApi.cpp + src/StatusGo/Messages/MessageDto.h + src/StatusGo/Messenger/Service.h src/StatusGo/Messenger/Service.cpp diff --git a/libs/StatusGoQt/src/StatusGo/Messages/InputMessage.cpp b/libs/StatusGoQt/src/StatusGo/Messages/InputMessage.cpp new file mode 100644 index 0000000000..afd271b5f9 --- /dev/null +++ b/libs/StatusGoQt/src/StatusGo/Messages/InputMessage.cpp @@ -0,0 +1,31 @@ +#include "InputMessage.h" + +#include +#include + +using namespace Status::StatusGo; + +Messages::InputMessage Messages::InputMessage::createTextMessage(const QString &message, const QString &chatId) +{ + return {message, chatId, ContentType::Text}; +} + +void Messages::to_json(json &j, const InputMessage &d) +{ + j = { + {"chatId", d.chatId}, + {"text", d.messageText}, + {"responseTo", d.replyTo}, + {"ensName", d.ensName}, + {"contentType", d.contentType}, + }; +} + +void Messages::from_json(const json &j, InputMessage &d) +{ + STATUS_READ_NLOHMAN_JSON_PROPERTY(chatId) + STATUS_READ_NLOHMAN_JSON_PROPERTY(messageText, "text") + STATUS_READ_NLOHMAN_JSON_PROPERTY(replyTo, "responseTo") + STATUS_READ_NLOHMAN_JSON_PROPERTY(ensName) + STATUS_READ_NLOHMAN_JSON_PROPERTY(contentType) +} diff --git a/libs/StatusGoQt/src/StatusGo/Messages/InputMessage.h b/libs/StatusGoQt/src/StatusGo/Messages/InputMessage.h new file mode 100644 index 0000000000..68989c29e1 --- /dev/null +++ b/libs/StatusGoQt/src/StatusGo/Messages/InputMessage.h @@ -0,0 +1,28 @@ +#pragma once + +#include "MessageDto.h" + +#include + +#include + +using json = nlohmann::json; + +namespace Status::StatusGo::Messages +{ + +struct InputMessage +{ + QString messageText; + QString chatId; + ContentType contentType = ContentType::Unknown; + QString replyTo; // Id of the message that we are replying to + QString ensName; // Ens name of the sender + + static InputMessage createTextMessage(const QString &message, const QString &chatId); +}; + +void to_json(json& j, const InputMessage& d); +void from_json(const json& j, InputMessage& d); + +} // namespace Status::StatusGo::Messages diff --git a/libs/StatusGoQt/src/StatusGo/Messages/MessageDto.h b/libs/StatusGoQt/src/StatusGo/Messages/MessageDto.h new file mode 100644 index 0000000000..a8d3f9ec79 --- /dev/null +++ b/libs/StatusGoQt/src/StatusGo/Messages/MessageDto.h @@ -0,0 +1,25 @@ +#pragma once + +namespace Status::StatusGo::Messages +{ + +/// @see status-go's protocol/protobuf/chat_message.proto ContentType +enum class ContentType +{ + Unknown = 0, + Text = 1, + Sticker = 2, + Status = 3, + Emoji = 4, + TransactionCommand = 5, + // 6 - private + Image = 7, + Audio = 8, + Community = 9, + // 10 - private + ContactRequest = 11, + DiscordMessage = 12, + IdentityVerification = 13 +}; + +} // namespace Status::StatusGo::Messages diff --git a/libs/StatusGoQt/src/StatusGo/Messages/MessagesApi.cpp b/libs/StatusGoQt/src/StatusGo/Messages/MessagesApi.cpp new file mode 100644 index 0000000000..2a194a9e22 --- /dev/null +++ b/libs/StatusGoQt/src/StatusGo/Messages/MessagesApi.cpp @@ -0,0 +1,21 @@ +#include "MessagesApi.h" +#include "Metadata/api_response.h" +#include "InputMessage.h" +#include "Utils.h" + +#include + +#include + +using json = nlohmann::json; + +using namespace Status::StatusGo; + +void Messages::sendMessage(const InputMessage &message) +{ + std::vector params{message}; + json inputJson = {{"jsonrpc", "2.0"}, {"method", "wakuext_sendChatMessage"}, {"params", params}}; + const auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); + const auto resultJson = json::parse(result); + checkPrivateRpcCallResultAndReportError(resultJson); +} diff --git a/libs/StatusGoQt/src/StatusGo/Messages/MessagesApi.h b/libs/StatusGoQt/src/StatusGo/Messages/MessagesApi.h new file mode 100644 index 0000000000..c777ff8d44 --- /dev/null +++ b/libs/StatusGoQt/src/StatusGo/Messages/MessagesApi.h @@ -0,0 +1,10 @@ +#pragma once + +namespace Status::StatusGo::Messages +{ +class InputMessage; + +/// \brief Sends chat message +void sendMessage(const InputMessage &message); + +} // namespace Status::StatusGo::Messages diff --git a/test/libs/StatusGoQt/test_messaging.cpp b/test/libs/StatusGoQt/test_messaging.cpp index e6cb0899a3..d960da4986 100644 --- a/test/libs/StatusGoQt/test_messaging.cpp +++ b/test/libs/StatusGoQt/test_messaging.cpp @@ -1,11 +1,13 @@ -#include - #include -#include - #include +#include +#include +#include +#include +#include + #include namespace fs = std::filesystem; @@ -36,4 +38,11 @@ TEST(MessagingApi, TestStartMessaging) ASSERT_TRUE(nodeReady); } +/// Simple test to validate sendChatMessage rpc function. \todo Expand it later. +TEST(MessagingApi, TestSendMessage) +{ + const auto message = StatusGo::Messages::InputMessage::createTextMessage("Hello Status", "someChatId"); + EXPECT_THROW( StatusGo::Messages::sendMessage(message), StatusGo::CallPrivateRpcError ); +} + } // namespace