Ring Daemon 16.0.0
Loading...
Searching...
No Matches
conversation.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#pragma once
18
23#include "jamidht/typers.h"
24
25#include <json/json.h>
26#include <msgpack.hpp>
27
28#include <functional>
29#include <string>
30#include <vector>
31#include <map>
32#include <memory>
33#include <set>
34
35#include <asio.hpp>
36
37namespace dhtnet {
38class ChannelSocket;
39} // namespace dhtnet
40
41namespace jami {
42
43namespace ConversationMapKeys {
44static constexpr const char* ID = "id";
45static constexpr const char* CREATED = "created";
46static constexpr const char* REMOVED = "removed";
47static constexpr const char* ERASED = "erased";
48static constexpr const char* MEMBERS = "members";
49static constexpr const char* LAST_DISPLAYED = "lastDisplayed";
50static constexpr const char* PREFERENCES = "preferences";
51static constexpr const char* ACTIVE_CALLS = "activeCalls";
52static constexpr const char* HOSTED_CALLS = "hostedCalls";
53static constexpr const char* CACHED = "cached";
54static constexpr const char* RECEIVED = "received";
55static constexpr const char* DECLINED = "declined";
56static constexpr const char* FROM = "from";
57static constexpr const char* CONVERSATIONID = "conversationId";
58static constexpr const char* METADATAS = "metadatas";
59} // namespace ConversationMapKeys
60
61namespace ConversationPreferences {
62static constexpr const char* HOST_CONFERENCES = "hostConferences";
63}
64
72{
73 std::string conversationId;
74 std::string from;
75 std::map<std::string, std::string> metadatas;
76
79
81 ConversationRequest(const Json::Value& json);
82
83 Json::Value toJson() const;
84 std::map<std::string, std::string> toMap() const;
85
86 bool operator==(const ConversationRequest& o) const
87 {
88 auto m = toMap();
89 auto om = o.toMap();
90 return m.size() == om.size() && std::equal(m.begin(), m.end(), om.begin());
91 }
92
93 bool isOneToOne() const {
94 try {
95 return metadatas.at("mode") == "0";
96 } catch (...) {}
97 return true;
98 }
99
100 MSGPACK_DEFINE_MAP(from, conversationId, metadatas, received, declined)
101};
102
104{
105 std::string id {};
109 std::set<std::string> members;
110 std::string lastDisplayed {};
111
112 ConvInfo() = default;
113 ConvInfo(const ConvInfo&) = default;
114 ConvInfo(ConvInfo&&) = default;
115 ConvInfo(const std::string& id) : id(id) {};
116 explicit ConvInfo(const Json::Value& json);
117
118 bool isRemoved() const { return removed >= created; }
119
120 ConvInfo& operator=(const ConvInfo&) = default;
122
123 Json::Value toJson() const;
124
125 MSGPACK_DEFINE_MAP(id, created, removed, erased, members, lastDisplayed)
126};
127
128class JamiAccount;
130class TransferManager;
131enum class ConversationMode;
132
133using OnPullCb = std::function<void(bool fetchOk)>;
135 = std::function<void(std::vector<std::map<std::string, std::string>>&& messages)>;
137 = std::function<void(std::vector<libjami::SwarmMessage>&& messages)>;
138using OnCommitCb = std::function<void(const std::string&)>;
139using OnDoneCb = std::function<void(bool, const std::string&)>;
140using OnMultiDoneCb = std::function<void(const std::vector<std::string>&)>;
141using OnMembersChanged = std::function<void(const std::set<std::string>&)>;
142using DeviceId = dht::PkId;
143using GitSocketList = std::map<DeviceId, std::shared_ptr<dhtnet::ChannelSocket>>;
144using ChannelCb = std::function<bool(const std::shared_ptr<dhtnet::ChannelSocket>&)>;
146 = std::function<void(const std::string&, const std::string&, ChannelCb&&, const std::string&)>;
147
148class Conversation : public std::enable_shared_from_this<Conversation>
149{
150public:
151 Conversation(const std::shared_ptr<JamiAccount>& account,
153 const std::string& otherMember = "");
154 Conversation(const std::shared_ptr<JamiAccount>& account,
155 const std::string& conversationId = "");
156 Conversation(const std::shared_ptr<JamiAccount>& account,
157 const std::string& remoteDevice,
158 const std::string& conversationId);
160
164 void monitor();
165
166#ifdef LIBJAMI_TEST
167 enum class BootstrapStatus { FAILED, FALLBACK, SUCCESS };
171 void onBootstrapStatus(const std::function<void(std::string, BootstrapStatus)>& cb);
172#endif
173
179 void bootstrap(std::function<void()> onBootstraped, const std::vector<DeviceId>& knownDevices);
180
187 std::vector<std::string> commitsEndedCalls();
188
190
200 void addSwarmChannel(std::shared_ptr<dhtnet::ChannelSocket> channel);
201
206 std::string id() const;
207
208 // Member management
214 void addMember(const std::string& contactUri, const OnDoneCb& cb = {});
215 void removeMember(const std::string& contactUri, bool isDevice, const OnDoneCb& cb = {});
228 std::vector<std::map<std::string, std::string>> getMembers(bool includeInvited = false,
229 bool includeLeft = false,
230 bool includeBanned = false) const;
231
237 std::set<std::string> memberUris(
238 std::string_view filter = {},
239 const std::set<MemberRole>& filteredRoles = {MemberRole::INVITED,
241 MemberRole::BANNED}) const;
242
247 std::vector<NodeId> peersToSyncWith() const;
252 bool isBootstraped() const;
259 std::string uriFromDevice(const std::string& deviceId) const;
260
265 std::string join();
266
272 bool isMember(const std::string& uri, bool includeInvited = false) const;
273 bool isBanned(const std::string& uri) const;
274
275 // Message send
276 void sendMessage(std::string&& message,
277 const std::string& type = "text/plain",
278 const std::string& replyTo = "",
279 OnCommitCb&& onCommit = {},
280 OnDoneCb&& cb = {});
281 void sendMessage(Json::Value&& message,
282 const std::string& replyTo = "",
283 OnCommitCb&& onCommit = {},
284 OnDoneCb&& cb = {});
285 // Note: used for replay. Should not be used by clients
286 void sendMessages(std::vector<Json::Value>&& messages, OnMultiDoneCb&& cb = {});
302 void clearCache();
308 std::optional<std::map<std::string, std::string>> getCommit(const std::string& commitId) const;
313 std::string lastCommitId() const;
314
322 bool pull(const std::string& deviceId, OnPullCb&& cb, std::string commitId = "");
330 void sync(const std::string& member,
331 const std::string& deviceId,
332 OnPullCb&& cb,
333 std::string commitId = "");
334
339 std::map<std::string, std::string> generateInvitation() const;
340
345 std::string leave();
346
352 void setRemovingFlag();
353
358 bool isRemoving();
359
363 void erase();
364
369 ConversationMode mode() const;
370
375 std::vector<std::string> getInitialMembers() const;
376 bool isInitialMember(const std::string& uri) const;
377
383 void updateInfos(const std::map<std::string, std::string>& map, const OnDoneCb& cb = {});
384
389 void updatePreferences(const std::map<std::string, std::string>& map);
390
395 std::map<std::string, std::string> infos() const;
401 std::map<std::string, std::string> preferences(bool includeLastModified) const;
402 std::vector<uint8_t> vCard() const;
403
405
409 std::shared_ptr<TransferManager> dataTransfer() const;
410
418 bool onFileChannelRequest(const std::string& member,
419 const std::string& fileId,
420 std::filesystem::path& path,
421 std::string& sha3sum) const;
431 bool downloadFile(const std::string& interactionId,
432 const std::string& fileId,
433 const std::string& path,
434 const std::string& member = "",
435 const std::string& deviceId = "");
436
447 void hasFetched(const std::string& deviceId, const std::string& commitId);
448
455 bool setMessageDisplayed(const std::string& uri, const std::string& interactionId);
467 std::map<std::string, std::map<std::string, std::string>> messageStatus() const;
479 void updateMessageStatus(const std::map<std::string, std::map<std::string, std::string>>& messageStatus);
480 void onMessageStatusChanged(const std::function<void(const std::map<std::string, std::map<std::string, std::string>>&)>& cb);
488 uint32_t countInteractions(const std::string& toId,
489 const std::string& fromId = "",
490 const std::string& authorUri = "") const;
498 void search(uint32_t req,
499 const Filter& filter,
500 const std::shared_ptr<std::atomic_int>& flag) const;
508 void hostConference(Json::Value&& message, OnDoneCb&& cb = {});
516 void removeActiveConference(Json::Value&& message, OnDoneCb&& cb = {});
522 bool isHosting(const std::string& confId) const;
527 std::vector<std::map<std::string, std::string>> currentCalls() const;
528
534 std::shared_ptr<dhtnet::ChannelSocket> gitSocket(const DeviceId& deviceId) const;
535 void addGitSocket(const DeviceId& deviceId, const std::shared_ptr<dhtnet::ChannelSocket>& socket);
536 void removeGitSocket(const DeviceId& deviceId);
537
541 void shutdownConnections();
547 bool hasSwarmChannel(const std::string& deviceId);
548
552 void connectivityChanged();
553
557 std::vector<jami::DeviceId> getDeviceIdList() const;
558
563 std::shared_ptr<Typers> typers() const;
564
565private:
566 std::shared_ptr<Conversation> shared()
567 {
568 return std::static_pointer_cast<Conversation>(shared_from_this());
569 }
570 std::shared_ptr<Conversation const> shared() const
571 {
572 return std::static_pointer_cast<Conversation const>(shared_from_this());
573 }
574 std::weak_ptr<Conversation> weak()
575 {
576 return std::static_pointer_cast<Conversation>(shared_from_this());
577 }
578 std::weak_ptr<Conversation const> weak() const
579 {
580 return std::static_pointer_cast<Conversation const>(shared_from_this());
581 }
582
583 // Private because of weak()
589 void checkBootstrapMember(const asio::error_code& ec,
590 std::vector<std::map<std::string, std::string>> members);
591
592 class Impl;
593 std::unique_ptr<Impl> pimpl_;
594};
595
596} // namespace jami
This class gives access to the git repository that represents the conversation.
bool pull(const std::string &deviceId, OnPullCb &&cb, std::string commitId="")
Fetch and merge from peer.
std::set< std::string > memberUris(std::string_view filter={}, const std::set< MemberRole > &filteredRoles={MemberRole::INVITED, MemberRole::LEFT, MemberRole::BANNED}) const
std::shared_ptr< Typers > typers() const
Get Typers object.
bool downloadFile(const std::string &interactionId, const std::string &fileId, const std::string &path, const std::string &member="", const std::string &deviceId="")
Adds a file to the waiting list and ask members.
void addGitSocket(const DeviceId &deviceId, const std::shared_ptr< dhtnet::ChannelSocket > &socket)
std::string leave()
Leave a conversation.
std::string id() const
Get conversation's id.
void clearCache()
Clear all cached messages.
std::vector< std::string > commitsEndedCalls()
Refresh active calls.
std::map< std::string, std::map< std::string, std::string > > messageStatus() const
Retrieve last displayed and fetch status per member.
void loadMessages2(const OnLoadMessages2 &cb, const LogOptions &options)
Get a range of messages.
bool isMember(const std::string &uri, bool includeInvited=false) const
Test if an URI is a member.
void search(uint32_t req, const Filter &filter, const std::shared_ptr< std::atomic_int > &flag) const
Search in the conversation via a filter.
std::vector< uint8_t > vCard() const
std::vector< std::string > getInitialMembers() const
One to one util, get initial members.
void connectivityChanged()
If we change from one network to one another, we will need to update the state of the connections.
std::shared_ptr< TransferManager > dataTransfer() const
Access to transfer manager.
void removeGitSocket(const DeviceId &deviceId)
std::vector< std::map< std::string, std::string > > currentCalls() const
Return current detected calls.
void clearFetched()
Reset fetched information.
void onMembersChanged(OnMembersChanged &&cb)
void bootstrap(std::function< void()> onBootstraped, const std::vector< DeviceId > &knownDevices)
Bootstrap swarm manager to other peers.
std::map< std::string, std::string > infos() const
Retrieve current infos (title, description, avatar, mode)
void monitor()
Print the state of the DRT linked to the conversation.
std::vector< NodeId > peersToSyncWith() const
Get peers to sync with.
void removeActiveConference(Json::Value &&message, OnDoneCb &&cb={})
Announce the end of a call.
bool isInitialMember(const std::string &uri) const
ConversationMode mode() const
Get conversation's mode.
std::string join()
Join a conversation.
void addSwarmChannel(std::shared_ptr< dhtnet::ChannelSocket > channel)
Add swarm connection to the DRT.
std::vector< jami::DeviceId > getDeviceIdList() const
bool setMessageDisplayed(const std::string &uri, const std::string &interactionId)
Store last read commit (returned in getMembers)
void loadMessages(OnLoadMessages cb, const LogOptions &options)
Get a range of messages.
void updateInfos(const std::map< std::string, std::string > &map, const OnDoneCb &cb={})
Change repository's infos.
void updateMessageStatus(const std::map< std::string, std::map< std::string, std::string > > &messageStatus)
Update fetch/read status.
void onMessageStatusChanged(const std::function< void(const std::map< std::string, std::map< std::string, std::string > > &)> &cb)
void shutdownConnections()
Stop SwarmManager, bootstrap and gitSockets.
void updatePreferences(const std::map< std::string, std::string > &map)
Change user's preferences.
void sendMessages(std::vector< Json::Value > &&messages, OnMultiDoneCb &&cb={})
std::vector< std::map< std::string, std::string > > getMembers(bool includeInvited=false, bool includeLeft=false, bool includeBanned=false) const
std::map< std::string, std::string > preferences(bool includeLastModified) const
Retrieve current preferences (color, notification, etc)
void sync(const std::string &member, const std::string &deviceId, OnPullCb &&cb, std::string commitId="")
Fetch new commits and re-ask for waiting files.
std::shared_ptr< dhtnet::ChannelSocket > gitSocket(const DeviceId &deviceId) const
Git operations will need a ChannelSocket for cloning/fetching commits Because libgit2 is a C library,...
void onNeedSocket(NeedSocketCb cb)
Set the callback that will be called whenever a new socket will be needed.
std::string uriFromDevice(const std::string &deviceId) const
Retrieve the uri from a deviceId.
std::optional< std::map< std::string, std::string > > getCommit(const std::string &commitId) const
Retrieve one commit.
void erase()
Erase all related datas.
void setRemovingFlag()
Set a conversation as removing (when loading convInfo and still not sync)
void sendMessage(std::string &&message, const std::string &type="text/plain", const std::string &replyTo="", OnCommitCb &&onCommit={}, OnDoneCb &&cb={})
void hasFetched(const std::string &deviceId, const std::string &commitId)
Store information about who fetch or not.
bool isHosting(const std::string &confId) const
Check if we're currently hosting this conference.
bool isBootstraped() const
Check if we're at least connected to one node.
std::string lastCommitId() const
Get last commit id.
bool isBanned(const std::string &uri) const
bool onFileChannelRequest(const std::string &member, const std::string &fileId, std::filesystem::path &path, std::string &sha3sum) const
Choose if we can accept channel request.
void addMember(const std::string &contactUri, const OnDoneCb &cb={})
Add conversation member.
bool hasSwarmChannel(const std::string &deviceId)
Used to avoid multiple connections, we just check if we got a swarm channel with a specific device.
bool isRemoving()
Check if we are removing the conversation.
void removeMember(const std::string &contactUri, bool isDevice, const OnDoneCb &cb={})
void hostConference(Json::Value &&message, OnDoneCb &&cb={})
Host a conference in the conversation.
uint32_t countInteractions(const std::string &toId, const std::string &fromId="", const std::string &authorUri="") const
Retrieve how many interactions there is from HEAD to interactionId.
std::map< std::string, std::string > generateInvitation() const
Generate an invitation to send to new contacts.
Ring Account is build on top of SIPAccountBase and uses DHT to handle call connectivity.
Definition jamiaccount.h:96
#define SUCCESS
static constexpr const char * CACHED
static constexpr const char * CREATED
static constexpr const char * REMOVED
static constexpr const char * ID
static constexpr const char * RECEIVED
static constexpr const char * METADATAS
static constexpr const char * MEMBERS
static constexpr const char * DECLINED
static constexpr const char * ERASED
static constexpr const char * FROM
static constexpr const char * CONVERSATIONID
static constexpr const char * HOSTED_CALLS
static constexpr const char * PREFERENCES
static constexpr const char * ACTIVE_CALLS
static constexpr const char * LAST_DISPLAYED
static constexpr const char * HOST_CONFERENCES
std::function< void(const std::string &, const std::string &, ChannelCb &&, const std::string &)> NeedSocketCb
std::function< void(std::vector< libjami::SwarmMessage > &&messages)> OnLoadMessages2
dht::PkId DeviceId
std::function< void(const std::vector< std::string > &)> OnMultiDoneCb
void emitSignal(Args... args)
Definition ring_signal.h:64
std::function< void(bool, const std::string &)> OnDoneCb
std::function< void(std::vector< std::map< std::string, std::string > > &&messages)> OnLoadMessages
std::function< bool(const std::shared_ptr< dhtnet::ChannelSocket > &)> ChannelCb
std::function< void(bool fetchOk)> OnPullCb
std::map< DeviceId, std::shared_ptr< dhtnet::ChannelSocket > > GitSocketList
std::function< void(const std::string &)> OnCommitCb
std::function< void(const std::set< std::string > &)> OnMembersChanged
std::set< std::string > members
ConvInfo & operator=(const ConvInfo &)=default
ConvInfo & operator=(ConvInfo &&)=default
ConvInfo(const ConvInfo &)=default
ConvInfo()=default
std::string lastDisplayed
Json::Value toJson() const
ConvInfo(const std::string &id)
ConvInfo(ConvInfo &&)=default
std::string id
bool isRemoved() const
A ConversationRequest is a request which corresponds to a trust request, but for conversations It's s...
std::map< std::string, std::string > metadatas
Json::Value toJson() const
std::map< std::string, std::string > toMap() const
bool operator==(const ConversationRequest &o) const