diff --git a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml index d78238d2748f051533f9dd554e970ac49e0b69c7..83d2702cdcc695eaaa27284b16cc972b3ae4cc57 100644 --- a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml +++ b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml @@ -540,6 +540,13 @@ </arg> </method> + <method name="getLastMessages" tp:name-for-bindings="getLastMessages"> + <arg type="s" name="accountID" direction="in"/> + <arg type="t" name="base_timestamp" direction="in"/> + <arg type="a(sa{ss}t)" name="messages" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="messages"/> + </method> + <method name="getMessageStatus" tp:name-for-bindings="getMessageStatus"> <arg type="t" name="id" direction="in"/> <arg type="i" name="status" direction="out"> diff --git a/bin/dbus/dbusconfigurationmanager.cpp b/bin/dbus/dbusconfigurationmanager.cpp index 0d11510b0a7e701c73cd28ed768b5d9ea0fa62cf..1e30e75ecbf3d758f9cb56247496eb71b316990e 100644 --- a/bin/dbus/dbusconfigurationmanager.cpp +++ b/bin/dbus/dbusconfigurationmanager.cpp @@ -153,6 +153,21 @@ DBusConfigurationManager::sendTextMessage(const std::string& accountID, const st return DRing::sendAccountTextMessage(accountID, to, payloads); } +std::vector<RingDBusMessage> +DBusConfigurationManager::getLastMessages(const std::string& accountID, const uint64_t& base_timestamp) +{ + auto messages = DRing::getLastMessages(accountID, base_timestamp); + std::vector<RingDBusMessage> result; + for (const auto& message : messages) { + RingDBusMessage m; + m._1 = message.from; + m._2 = message.payloads; + m._3 = message.received; + result.emplace_back(m); + } + return result; +} + auto DBusConfigurationManager::getMessageStatus(const uint64_t& id) -> decltype(DRing::getMessageStatus(id)) { diff --git a/bin/dbus/dbusconfigurationmanager.h b/bin/dbus/dbusconfigurationmanager.h index 2d76ab8d2b00a5d68214a25fc000b1be6a612d8f..894241d2cfa9af2c4e3e2e9c27b0e6fccfebdaa1 100644 --- a/bin/dbus/dbusconfigurationmanager.h +++ b/bin/dbus/dbusconfigurationmanager.h @@ -49,6 +49,8 @@ #pragma GCC diagnostic warning "-Wunused-but-set-variable" #endif +using RingDBusMessage = DBus::Struct<std::string, std::map<std::string, std::string>, long unsigned int>; + class DBusConfigurationManager : public cx::ring::Ring::ConfigurationManager_adaptor, public DBus::IntrospectableAdaptor, @@ -80,6 +82,7 @@ class DBusConfigurationManager : void sendRegister(const std::string& accoundID, const bool& enable); void registerAllAccounts(void); uint64_t sendTextMessage(const std::string& accoundID, const std::string& to, const std::map<std::string, std::string>& payloads); + std::vector<RingDBusMessage> getLastMessages(const std::string& accountID, const uint64_t& base_timestamp); int getMessageStatus(const uint64_t& id); std::map<std::string, std::string> getTlsDefaultSettings(); std::vector<std::string> getSupportedCiphers(const std::string& accountID); diff --git a/bin/jni/configurationmanager.i b/bin/jni/configurationmanager.i index 71179f58a6aa6e0d9d6218ab4b8c5543aeb9f7fa..600ac6315d19eb9847b8a3f1ccb46da85322ad36 100644 --- a/bin/jni/configurationmanager.i +++ b/bin/jni/configurationmanager.i @@ -60,9 +60,17 @@ public: %} %feature("director") ConfigurationCallback; +%template(MessageVect) std::vector<DRing::Message>; namespace DRing { +struct Message +{ + std::string from; + std::map<std::string, std::string> payloads; + uint64_t received; +}; + std::map<std::string, std::string> getAccountDetails(const std::string& accountID); std::map<std::string, std::string> getVolatileAccountDetails(const std::string& accountID); void setAccountDetails(const std::string& accountID, const std::map<std::string, std::string>& details); @@ -74,6 +82,7 @@ std::vector<std::string> getAccountList(); void sendRegister(const std::string& accountID, bool enable); void registerAllAccounts(void); uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& message); +std::vector<DRing::Message> getLastMessages(const std::string& accountID, uint64_t base_timestamp); int getMessageStatus(uint64_t id); bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name); diff --git a/bin/nodejs/configurationmanager.i b/bin/nodejs/configurationmanager.i index c56c99e81ea15f7b4010fcb28b34a003e671ad64..5170e1f239baba78753a47968237c71f275644e5 100644 --- a/bin/nodejs/configurationmanager.i +++ b/bin/nodejs/configurationmanager.i @@ -60,6 +60,13 @@ public: namespace DRing { +struct Message +{ + std::string from; + std::map<std::string, std::string> payloads; + uint64_t received; +}; + std::map<std::string, std::string> getAccountDetails(const std::string& accountID); std::map<std::string, std::string> getVolatileAccountDetails(const std::string& accountID); void setAccountDetails(const std::string& accountID, const std::map<std::string, std::string>& details); @@ -71,6 +78,7 @@ std::vector<std::string> getAccountList(); void sendRegister(const std::string& accountID, bool enable); void registerAllAccounts(void); uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& message); +std::vector<Message> getLastMessages(const std::string& accountID, const uint64_t& base_timestamp); int getMessageStatus(uint64_t id); bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name); diff --git a/src/account.h b/src/account.h index c71d8e55da945f885109ffc22eaf14b4269e258e..027b429ca3ff18e9a4fc7934c08cf74d2668907f 100644 --- a/src/account.h +++ b/src/account.h @@ -27,6 +27,7 @@ #include "config.h" #endif +#include "configurationmanager_interface.h" #include "noncopyable.h" #include "config/serializable.h" #include "registration_states.h" @@ -34,7 +35,7 @@ #include "ip_utils.h" #include "media_codec.h" #include "logger.h" -#include "compiler_intrinsics.h" // UNUSED +#include "compiler_intrinsics.h" // include the "UNUSED" macro #include <functional> #include <string> @@ -155,6 +156,10 @@ class Account : public Serializable, public std::enable_shared_from_this<Account virtual uint64_t sendTextMessage(const std::string& to UNUSED, const std::map<std::string, std::string>& payloads UNUSED) { return 0; } + virtual std::vector<DRing::Message> getLastMessages(const uint64_t& base_timestamp) { + return {}; + } + /** * Return the status corresponding to the token. */ diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp index 1f4d11c341326a4ab3fd930f5ebef256592979ca..6cb22bd5426104ee221f1c69e1d7d4963357e069 100644 --- a/src/client/configurationmanager.cpp +++ b/src/client/configurationmanager.cpp @@ -270,6 +270,12 @@ sendAccountTextMessage(const std::string& accountID, const std::string& to, cons return ring::Manager::instance().sendTextMessage(accountID, to, payloads); } +std::vector<Message> +getLastMessages(const std::string& accountID, const uint64_t& base_timestamp) +{ + return ring::Manager::instance().getLastMessages(accountID, base_timestamp); +} + int getMessageStatus(uint64_t id) { diff --git a/src/dring/configurationmanager_interface.h b/src/dring/configurationmanager_interface.h index 1e107cbe4900f3e6d24c42cb858dd10cb5420ffc..971e081eacee82cd2b854f564dd65ee98ea3b386 100644 --- a/src/dring/configurationmanager_interface.h +++ b/src/dring/configurationmanager_interface.h @@ -40,6 +40,13 @@ namespace DRing { +struct Message +{ + std::string from; + std::map<std::string, std::string> payloads; + uint64_t received; +}; + void registerConfHandlers(const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>&); std::map<std::string, std::string> getAccountDetails(const std::string& accountID); @@ -65,6 +72,7 @@ std::vector<std::string> getAccountList(); void sendRegister(const std::string& accountID, bool enable); void registerAllAccounts(void); uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& payloads); +std::vector<Message> getLastMessages(const std::string& accountID, const uint64_t& base_timestamp); int getMessageStatus(uint64_t id); diff --git a/src/manager.cpp b/src/manager.cpp index 40e7081a1616564b2d0eda999782bb00ee595e5f..2b42471b5824908fa3ef3bed51c3ebe2f323f38e 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -3150,4 +3150,12 @@ Manager::getVideoManager() const } #endif +std::vector<DRing::Message> +Manager::getLastMessages(const std::string& accountID, const uint64_t& base_timestamp) +{ + if (const auto acc = getAccount(accountID)) + return acc->getLastMessages(base_timestamp); + return {}; +} + } // namespace ring diff --git a/src/manager.h b/src/manager.h index 5f35d2619cece7aac6e0f525b1dd34ec2516adc9..23df1ac6f2b6b825793ea0b710e569459c3a78df 100644 --- a/src/manager.h +++ b/src/manager.h @@ -893,6 +893,8 @@ class Manager { std::unique_ptr<DataTransferFacade> dataTransfers; + std::vector<DRing::Message> getLastMessages(const std::string& accountID, const uint64_t& base_timestamp); + private: Manager(); ~Manager(); diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index a5d84e69d22f1c389b86f479f9fc59788d022c08..22dfc80d0af4645853d9a98a18164b525e632aaf 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -3457,6 +3457,7 @@ void RingAccount::pushNotificationReceived(const std::string& from, const std::m dht_.pushNotificationReceived(data); } + std::string RingAccount::getUserUri() const { @@ -3467,4 +3468,10 @@ RingAccount::getUserUri() const return username_; } + +std::vector<DRing::Message> +RingAccount::getLastMessages(const uint64_t& base_timestamp) +{ + return SIPAccountBase::getLastMessages(base_timestamp); +} } // namespace ring diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index d6021a78c43608a0226025a07aa368b6b724362f..bd99f8dda234d749c67664f172f262780cab8830 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -378,6 +378,12 @@ class RingAccount : public SIPAccountBase { std::string getUserUri() const override; + /** + * Get last messages (should be used to retrieve messages when launching the client) + * @param base_timestamp + */ + std::vector<DRing::Message> getLastMessages(const uint64_t& base_timestamp); + private: NON_COPYABLE(RingAccount); diff --git a/src/sip/sipaccountbase.cpp b/src/sip/sipaccountbase.cpp index 4457fadbe10b115688e631ac9059f13f54ddec56..0799e571cd8db527d9316d9077220822c7b3ef97 100644 --- a/src/sip/sipaccountbase.cpp +++ b/src/sip/sipaccountbase.cpp @@ -42,6 +42,7 @@ #include "fileutils.h" #include "sip_utils.h" +#include <ctime> #include <type_traits> namespace ring { @@ -386,6 +387,15 @@ SIPAccountBase::onTextMessage(const std::string& from, { RING_DBG("Text message received from %s, %zu part(s)", from.c_str(), payloads.size()); emitSignal<DRing::ConfigurationSignal::IncomingAccountMessage>(accountID_, from, payloads); + DRing::Message message; + message.from = from; + message.payloads = payloads; + message.received = std::time(nullptr); + std::lock_guard<std::mutex> lck(mutexLastMessages_); + lastMessages_.emplace_back(message); + while (lastMessages_.size() > MAX_WAITING_MESSAGES_SIZE) { + lastMessages_.pop_front(); + } } void diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index a1ecedcb30591d259b810037b1f421e6f8af9c46..181269890d2ecdac9f2b8199618e819361491f5b 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -18,8 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef SIPACCOUNTBASE_H -#define SIPACCOUNTBASE_H +#pragma once #ifdef HAVE_CONFIG_H #include "config.h" @@ -35,9 +34,11 @@ #include <pjsip/sip_types.h> #include <array> -#include <vector> +#include <deque> #include <map> #include <memory> +#include <mutex> +#include <vector> #ifdef _WIN32 typedef uint16_t in_port_t; @@ -276,6 +277,19 @@ public: virtual std::string getUserUri() const = 0; + std::vector<DRing::Message> getLastMessages(const uint64_t& base_timestamp) { + std::lock_guard<std::mutex> lck(mutexLastMessages_); + auto it = lastMessages_.begin(); + size_t num = lastMessages_.size(); + while (it != lastMessages_.end() and it->received <= base_timestamp) { + num--; + ++it; + } + if (num == 0) + return {}; + return {it, lastMessages_.end()}; + } + public: // overloaded methods virtual void flush() override; @@ -416,11 +430,19 @@ protected: uint16_t getRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const; uint16_t acquireRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const; + /** + * The deamon can be launched without any client (or with a non ready client) + * Like call and file transfer, a client should be able to retrieve current messages. + * To avoid to explode the size in memory, this container should be limited. + * We don't want to see monsters in memory. + */ + std::mutex mutexLastMessages_; + static constexpr size_t MAX_WAITING_MESSAGES_SIZE = 1000; + std::deque<DRing::Message> lastMessages_; + private: NON_COPYABLE(SIPAccountBase); }; } // namespace ring - -#endif