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 @@
</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">
......
......@@ -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))
{
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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.
*/
......
......@@ -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)
{
......
......@@ -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);
......
......@@ -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
......@@ -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();
......
......@@ -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
......@@ -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);
......
......@@ -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
......
......@@ -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
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