Commit 6fc81302 authored by Sébastien Blin's avatar Sébastien Blin

sipaccountbase: add getLastMessages()

Because a client can receives messages before a client is ready to
receive it and because the daemon does not store any message, we
should have, like calls or file transfers, have a method to get
these messages.

So, this patch introduces a new method which gives the ability to
retrieve messages since the daemon has been launched. To do that,
when the daemon will receives a new message, it will store this
message into a queue (limited to 1000 messages) and save the
related timestamp. When the client is ready it can call getLastMessages
with its last known timestamp. This method will return all messages
received after this timestamp.

Note: the perfect way to do that is to store messages directly in
the daemon not clients. We also need some synchronization processes.

Change-Id: Iceb1654088a843f9be5b4a47bcc23201e9b38c01
parent c21c5b77
...@@ -540,6 +540,13 @@ ...@@ -540,6 +540,13 @@
</arg> </arg>
</method> </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"> <method name="getMessageStatus" tp:name-for-bindings="getMessageStatus">
<arg type="t" name="id" direction="in"/> <arg type="t" name="id" direction="in"/>
<arg type="i" name="status" direction="out"> <arg type="i" name="status" direction="out">
......
...@@ -153,6 +153,21 @@ DBusConfigurationManager::sendTextMessage(const std::string& accountID, const st ...@@ -153,6 +153,21 @@ DBusConfigurationManager::sendTextMessage(const std::string& accountID, const st
return DRing::sendAccountTextMessage(accountID, to, payloads); 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 auto
DBusConfigurationManager::getMessageStatus(const uint64_t& id) -> decltype(DRing::getMessageStatus(id)) DBusConfigurationManager::getMessageStatus(const uint64_t& id) -> decltype(DRing::getMessageStatus(id))
{ {
......
...@@ -49,6 +49,8 @@ ...@@ -49,6 +49,8 @@
#pragma GCC diagnostic warning "-Wunused-but-set-variable" #pragma GCC diagnostic warning "-Wunused-but-set-variable"
#endif #endif
using RingDBusMessage = DBus::Struct<std::string, std::map<std::string, std::string>, long unsigned int>;
class DBusConfigurationManager : class DBusConfigurationManager :
public cx::ring::Ring::ConfigurationManager_adaptor, public cx::ring::Ring::ConfigurationManager_adaptor,
public DBus::IntrospectableAdaptor, public DBus::IntrospectableAdaptor,
...@@ -80,6 +82,7 @@ class DBusConfigurationManager : ...@@ -80,6 +82,7 @@ class DBusConfigurationManager :
void sendRegister(const std::string& accoundID, const bool& enable); void sendRegister(const std::string& accoundID, const bool& enable);
void registerAllAccounts(void); void registerAllAccounts(void);
uint64_t sendTextMessage(const std::string& accoundID, const std::string& to, const std::map<std::string, std::string>& payloads); 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); int getMessageStatus(const uint64_t& id);
std::map<std::string, std::string> getTlsDefaultSettings(); std::map<std::string, std::string> getTlsDefaultSettings();
std::vector<std::string> getSupportedCiphers(const std::string& accountID); std::vector<std::string> getSupportedCiphers(const std::string& accountID);
......
...@@ -60,9 +60,17 @@ public: ...@@ -60,9 +60,17 @@ public:
%} %}
%feature("director") ConfigurationCallback; %feature("director") ConfigurationCallback;
%template(MessageVect) std::vector<DRing::Message>;
namespace DRing { 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> getAccountDetails(const std::string& accountID);
std::map<std::string, std::string> getVolatileAccountDetails(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); void setAccountDetails(const std::string& accountID, const std::map<std::string, std::string>& details);
...@@ -74,6 +82,7 @@ std::vector<std::string> getAccountList(); ...@@ -74,6 +82,7 @@ std::vector<std::string> getAccountList();
void sendRegister(const std::string& accountID, bool enable); void sendRegister(const std::string& accountID, bool enable);
void registerAllAccounts(void); void registerAllAccounts(void);
uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& message); 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); int getMessageStatus(uint64_t id);
bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name); bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name);
......
...@@ -60,6 +60,13 @@ public: ...@@ -60,6 +60,13 @@ public:
namespace DRing { 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> getAccountDetails(const std::string& accountID);
std::map<std::string, std::string> getVolatileAccountDetails(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); void setAccountDetails(const std::string& accountID, const std::map<std::string, std::string>& details);
...@@ -71,6 +78,7 @@ std::vector<std::string> getAccountList(); ...@@ -71,6 +78,7 @@ std::vector<std::string> getAccountList();
void sendRegister(const std::string& accountID, bool enable); void sendRegister(const std::string& accountID, bool enable);
void registerAllAccounts(void); void registerAllAccounts(void);
uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& message); 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); int getMessageStatus(uint64_t id);
bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name); bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "config.h" #include "config.h"
#endif #endif
#include "configurationmanager_interface.h"
#include "noncopyable.h" #include "noncopyable.h"
#include "config/serializable.h" #include "config/serializable.h"
#include "registration_states.h" #include "registration_states.h"
...@@ -34,7 +35,7 @@ ...@@ -34,7 +35,7 @@
#include "ip_utils.h" #include "ip_utils.h"
#include "media_codec.h" #include "media_codec.h"
#include "logger.h" #include "logger.h"
#include "compiler_intrinsics.h" // UNUSED #include "compiler_intrinsics.h" // include the "UNUSED" macro
#include <functional> #include <functional>
#include <string> #include <string>
...@@ -155,6 +156,10 @@ class Account : public Serializable, public std::enable_shared_from_this<Account ...@@ -155,6 +156,10 @@ class Account : public Serializable, public std::enable_shared_from_this<Account
virtual uint64_t sendTextMessage(const std::string& to UNUSED, virtual uint64_t sendTextMessage(const std::string& to UNUSED,
const std::map<std::string, std::string>& payloads UNUSED) { return 0; } 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. * Return the status corresponding to the token.
*/ */
......
...@@ -270,6 +270,12 @@ sendAccountTextMessage(const std::string& accountID, const std::string& to, cons ...@@ -270,6 +270,12 @@ sendAccountTextMessage(const std::string& accountID, const std::string& to, cons
return ring::Manager::instance().sendTextMessage(accountID, to, payloads); 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 int
getMessageStatus(uint64_t id) getMessageStatus(uint64_t id)
{ {
......
...@@ -40,6 +40,13 @@ ...@@ -40,6 +40,13 @@
namespace DRing { 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>>&); void registerConfHandlers(const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>&);
std::map<std::string, std::string> getAccountDetails(const std::string& accountID); std::map<std::string, std::string> getAccountDetails(const std::string& accountID);
...@@ -65,6 +72,7 @@ std::vector<std::string> getAccountList(); ...@@ -65,6 +72,7 @@ std::vector<std::string> getAccountList();
void sendRegister(const std::string& accountID, bool enable); void sendRegister(const std::string& accountID, bool enable);
void registerAllAccounts(void); void registerAllAccounts(void);
uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& payloads); 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); int getMessageStatus(uint64_t id);
......
...@@ -3150,4 +3150,12 @@ Manager::getVideoManager() const ...@@ -3150,4 +3150,12 @@ Manager::getVideoManager() const
} }
#endif #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 } // namespace ring
...@@ -893,6 +893,8 @@ class Manager { ...@@ -893,6 +893,8 @@ class Manager {
std::unique_ptr<DataTransferFacade> dataTransfers; std::unique_ptr<DataTransferFacade> dataTransfers;
std::vector<DRing::Message> getLastMessages(const std::string& accountID, const uint64_t& base_timestamp);
private: private:
Manager(); Manager();
~Manager(); ~Manager();
......
...@@ -3457,6 +3457,7 @@ void RingAccount::pushNotificationReceived(const std::string& from, const std::m ...@@ -3457,6 +3457,7 @@ void RingAccount::pushNotificationReceived(const std::string& from, const std::m
dht_.pushNotificationReceived(data); dht_.pushNotificationReceived(data);
} }
std::string std::string
RingAccount::getUserUri() const RingAccount::getUserUri() const
{ {
...@@ -3467,4 +3468,10 @@ RingAccount::getUserUri() const ...@@ -3467,4 +3468,10 @@ RingAccount::getUserUri() const
return username_; return username_;
} }
std::vector<DRing::Message>
RingAccount::getLastMessages(const uint64_t& base_timestamp)
{
return SIPAccountBase::getLastMessages(base_timestamp);
}
} // namespace ring } // namespace ring
...@@ -378,6 +378,12 @@ class RingAccount : public SIPAccountBase { ...@@ -378,6 +378,12 @@ class RingAccount : public SIPAccountBase {
std::string getUserUri() const override; 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: private:
NON_COPYABLE(RingAccount); NON_COPYABLE(RingAccount);
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "fileutils.h" #include "fileutils.h"
#include "sip_utils.h" #include "sip_utils.h"
#include <ctime>
#include <type_traits> #include <type_traits>
namespace ring { namespace ring {
...@@ -386,6 +387,15 @@ SIPAccountBase::onTextMessage(const std::string& from, ...@@ -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()); RING_DBG("Text message received from %s, %zu part(s)", from.c_str(), payloads.size());
emitSignal<DRing::ConfigurationSignal::IncomingAccountMessage>(accountID_, from, payloads); 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 void
......
...@@ -18,8 +18,7 @@ ...@@ -18,8 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef SIPACCOUNTBASE_H #pragma once
#define SIPACCOUNTBASE_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
...@@ -35,9 +34,11 @@ ...@@ -35,9 +34,11 @@
#include <pjsip/sip_types.h> #include <pjsip/sip_types.h>
#include <array> #include <array>
#include <vector> #include <deque>
#include <map> #include <map>
#include <memory> #include <memory>
#include <mutex>
#include <vector>
#ifdef _WIN32 #ifdef _WIN32
typedef uint16_t in_port_t; typedef uint16_t in_port_t;
...@@ -276,6 +277,19 @@ public: ...@@ -276,6 +277,19 @@ public:
virtual std::string getUserUri() const = 0; 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 public: // overloaded methods
virtual void flush() override; virtual void flush() override;
...@@ -416,11 +430,19 @@ protected: ...@@ -416,11 +430,19 @@ protected:
uint16_t getRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const; uint16_t getRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const;
uint16_t acquireRandomEvenPort(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: private:
NON_COPYABLE(SIPAccountBase); NON_COPYABLE(SIPAccountBase);
}; };
} // namespace ring } // namespace ring
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment