Ring Daemon 16.0.0
Loading...
Searching...
No Matches
conversation_module.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
19#include "scheduled_executor.h"
24
25#include <mutex>
26#include <msgpack.hpp>
27
28namespace jami {
29static constexpr const char MIME_TYPE_INVITE[] {"application/invite"};
30static constexpr const char MIME_TYPE_GIT[] {"application/im-gitmessage-id"};
31
32class SIPCall;
33
34struct SyncMsg
35{
37 std::map<std::string, ConvInfo> c;
38 std::map<std::string, ConversationRequest> cr;
39 // p is conversation's preferences. It's not stored in c, as
40 // we can update the preferences without touching any confInfo.
41 std::map<std::string, std::map<std::string, std::string>> p;
42 // Last displayed messages [[deprecated]]
43 std::map<std::string, std::map<std::string, std::string>> ld;
44 // Read & fetched status
45 /*
46 * {{ convId,
47 * { memberUri,, {
48 * {"fetch", "commitId"},
49 * {"fetched_ts", "timestamp"},
50 * {"read", "commitId"},
51 * {"read_ts", "timestamp"}
52 * }
53 * }}
54 */
55 std::map<std::string, std::map<std::string, std::map<std::string, std::string>>> ms;
56
57 MSGPACK_DEFINE(ds, c, cr, p, ld, ms)
58};
59
60using ChannelCb = std::function<bool(const std::shared_ptr<dhtnet::ChannelSocket>&)>;
61using NeedSocketCb
62 = std::function<void(const std::string&, const std::string&, ChannelCb&&, const std::string&)>;
63using SengMsgCb = std::function<
64 uint64_t(const std::string&, const DeviceId&, std::map<std::string, std::string>, uint64_t)>;
65using NeedsSyncingCb = std::function<void(std::shared_ptr<SyncMsg>&&)>;
66using OneToOneRecvCb = std::function<void(const std::string&, const std::string&)>;
67
69{
70public:
71 ConversationModule(std::shared_ptr<JamiAccount> account,
72 std::shared_ptr<AccountManager> accountManager,
75 NeedSocketCb&& onNeedSocket,
78 bool autoLoadConversations = true);
80
81 void setAccountManager(std::shared_ptr<AccountManager> accountManager);
82
86 void loadConversations();
87
88 void loadSingleConversation(const std::string& convId);
89
90#ifdef LIBJAMI_TEST
91 void onBootstrapStatus(const std::function<void(std::string, Conversation::BootstrapStatus)>& cb);
92#endif
93
94 void monitor();
95
99 void bootstrap(const std::string& convId = "");
100
104 void clearPendingFetch();
105
109 void reloadRequests();
110
114 std::vector<std::string> getConversations() const;
115
121 std::string getOneToOneConversation(const std::string& uri) const noexcept;
122
130 bool updateConvForContact(const std::string& uri,
131 const std::string& oldConv,
132 const std::string& newConv);
133
137 std::vector<std::map<std::string, std::string>> getConversationRequests() const;
138
146 void onTrustRequest(const std::string& uri,
147 const std::string& conversationId,
148 const std::vector<uint8_t>& payload,
149 time_t received);
150
156 void onConversationRequest(const std::string& from, const Json::Value& value);
157
163 std::string peerFromConversationRequest(const std::string& convId) const;
164
171 void onNeedConversationRequest(const std::string& from, const std::string& conversationId);
172
178 void acceptConversationRequest(const std::string& conversationId,
179 const std::string& deviceId = "");
180
185 void declineConversationRequest(const std::string& conversationId);
186
194 void cloneConversationFrom(const std::string& conversationId,
195 const std::string& uri,
196 const std::string& oldConvId = "");
197
205 const dht::InfoHash& otherMember = {});
206
207 // Message send/load
208 void sendMessage(const std::string& conversationId,
209 Json::Value&& value,
210 const std::string& replyTo = "",
211 bool announce = true,
212 OnCommitCb&& onCommit = {},
213 OnDoneCb&& cb = {});
214
215 void sendMessage(const std::string& conversationId,
216 std::string message,
217 const std::string& replyTo = "",
218 const std::string& type = "text/plain",
219 bool announce = true,
220 OnCommitCb&& onCommit = {},
221 OnDoneCb&& cb = {});
222
223 void editMessage(const std::string& conversationId,
224 const std::string& newBody,
225 const std::string& editedId);
226 void reactToMessage(const std::string& conversationId,
227 const std::string& newBody,
228 const std::string& reactToId);
229
236 void addCallHistoryMessage(const std::string& uri, uint64_t duration_ms, const std::string& reason);
237
238 // Received that a peer displayed a message
239 bool onMessageDisplayed(const std::string& peer,
240 const std::string& conversationId,
241 const std::string& interactionId);
242 std::map<std::string, std::map<std::string, std::map<std::string, std::string>>> convMessageStatus() const;
243
251 uint32_t loadConversationMessages(const std::string& conversationId,
252 const std::string& fromMessage = "",
253 size_t n = 0);
254 uint32_t loadConversation(const std::string& conversationId,
255 const std::string& fromMessage = "",
256 size_t n = 0);
257 uint32_t loadConversationUntil(const std::string& conversationId,
258 const std::string& fromMessage,
259 const std::string& to);
260 uint32_t loadSwarmUntil(const std::string& conversationId,
261 const std::string& fromMessage,
262 const std::string& toMessage);
267 void clearCache(const std::string& conversationId);
268
269 // File transfer
275 std::shared_ptr<TransferManager> dataTransfer(const std::string& id) const;
276
284 bool onFileChannelRequest(const std::string& conversationId,
285 const std::string& member,
286 const std::string& fileId,
287 bool verifyShaSum = true) const;
288
296 bool downloadFile(const std::string& conversationId,
297 const std::string& interactionId,
298 const std::string& fileId,
299 const std::string& path);
300
301 // Sync
305 void syncConversations(const std::string& peer, const std::string& deviceId);
306
313 void onSyncData(const SyncMsg& msg, const std::string& peerId, const std::string& deviceId);
314
320 bool needsSyncingWith(const std::string& memberUri, const std::string& deviceId) const;
321
330 void setFetched(const std::string& conversationId,
331 const std::string& deviceId,
332 const std::string& commit);
333
341 void fetchNewCommits(const std::string& peer,
342 const std::string& deviceId,
343 const std::string& conversationId,
344 const std::string& commitId);
345
346 // Conversation's member
353 void addConversationMember(const std::string& conversationId,
354 const dht::InfoHash& contactUri,
355 bool sendRequest = true);
362 void removeConversationMember(const std::string& conversationId,
363 const dht::InfoHash& contactUri,
364 bool isDevice = false);
371 std::vector<std::map<std::string, std::string>> getConversationMembers(
372 const std::string& conversationId, bool includeBanned = false) const;
380 uint32_t countInteractions(const std::string& convId,
381 const std::string& toId,
382 const std::string& fromId,
383 const std::string& authorUri) const;
384
392 void search(uint32_t req, const std::string& convId, const Filter& filter) const;
393
394 // Conversation's infos management
401 void updateConversationInfos(const std::string& conversationId,
402 const std::map<std::string, std::string>& infos,
403 bool sync = true);
404 std::map<std::string, std::string> conversationInfos(const std::string& conversationId) const;
410 void setConversationPreferences(const std::string& conversationId,
411 const std::map<std::string, std::string>& prefs);
412 std::map<std::string, std::string> getConversationPreferences(const std::string& conversationId,
413 bool includeCreated = false) const;
417 std::map<std::string, std::map<std::string, std::string>> convPreferences() const;
418 // Get the map into a VCard format for storing
419 std::vector<uint8_t> conversationVCard(const std::string& conversationId) const;
420
426 bool isBanned(const std::string& convId, const std::string& uri) const;
427
428 // Remove swarm
434 void removeContact(const std::string& uri, bool ban);
435
441 bool removeConversation(const std::string& conversationId);
442 void initReplay(const std::string& oldConvId, const std::string& newConvId);
449 bool isHosting(const std::string& conversationId, const std::string& confId) const;
455 std::vector<std::map<std::string, std::string>> getActiveCalls(
456 const std::string& conversationId) const;
464 std::shared_ptr<SIPCall> call(const std::string& url,
465 const std::vector<libjami::MediaMap>& mediaList,
466 std::function<void(const std::string&, const DeviceId&, const std::shared_ptr<SIPCall>&)>&& cb);
467 void hostConference(const std::string& conversationId,
468 const std::string& confId,
469 const std::string& callId,
470 const std::vector<libjami::MediaMap>& mediaList = {});
471
472 // The following methods modify what is stored on the disk
473 static void saveConvInfos(const std::string& accountId,
474 const std::map<std::string, ConvInfo>& conversations);
475 static void saveConvInfosToPath(const std::filesystem::path& path,
476 const std::map<std::string, ConvInfo>& conversations);
477 static void saveConvRequests(
478 const std::string& accountId,
479 const std::map<std::string, ConversationRequest>& conversationsRequests);
480 static void saveConvRequestsToPath(
481 const std::filesystem::path& path,
482 const std::map<std::string, ConversationRequest>& conversationsRequests);
483
484 static std::map<std::string, ConvInfo> convInfos(const std::string& accountId);
485 static std::map<std::string, ConvInfo> convInfosFromPath(const std::filesystem::path& path);
486 static std::map<std::string, ConversationRequest> convRequests(const std::string& accountId);
487 static std::map<std::string, ConversationRequest> convRequestsFromPath(
488 const std::filesystem::path& path);
489 void addConvInfo(const ConvInfo& info);
490
495 std::shared_ptr<Conversation> getConversation(const std::string& convId);
502 std::shared_ptr<dhtnet::ChannelSocket> gitSocket(std::string_view deviceId,
503 std::string_view convId) const;
504 void removeGitSocket(std::string_view deviceId, std::string_view convId);
505 void addGitSocket(std::string_view deviceId,
506 std::string_view convId,
507 const std::shared_ptr<dhtnet::ChannelSocket>& channel);
511 void shutdownConnections();
517 void addSwarmChannel(const std::string& conversationId,
518 std::shared_ptr<dhtnet::ChannelSocket> socket);
522 void connectivityChanged();
523
529 std::shared_ptr<Typers> getTypers(const std::string& convId);
530
531private:
532 class Impl;
533 std::shared_ptr<Impl> pimpl_;
534};
535
536} // namespace jami
void removeContact(const std::string &uri, bool ban)
Remove one to one conversations related to a contact.
void addSwarmChannel(const std::string &conversationId, std::shared_ptr< dhtnet::ChannelSocket > socket)
Add a swarm connection.
void onConversationRequest(const std::string &from, const Json::Value &value)
Called when receiving a new conversation's request.
bool onMessageDisplayed(const std::string &peer, const std::string &conversationId, const std::string &interactionId)
void editMessage(const std::string &conversationId, const std::string &newBody, const std::string &editedId)
static void saveConvInfosToPath(const std::filesystem::path &path, const std::map< std::string, ConvInfo > &conversations)
static void saveConvInfos(const std::string &accountId, const std::map< std::string, ConvInfo > &conversations)
void search(uint32_t req, const std::string &convId, const Filter &filter) const
Search in conversations via a filter.
void initReplay(const std::string &oldConvId, const std::string &newConvId)
std::vector< std::map< std::string, std::string > > getConversationRequests() const
Return conversation's requests.
void syncConversations(const std::string &peer, const std::string &deviceId)
Sync conversations with detected peer.
std::shared_ptr< Conversation > getConversation(const std::string &convId)
Get a conversation.
void removeGitSocket(std::string_view deviceId, std::string_view convId)
void connectivityChanged()
Triggers a bucket maintainance for DRTs.
void setAccountManager(std::shared_ptr< AccountManager > accountManager)
void addConversationMember(const std::string &conversationId, const dht::InfoHash &contactUri, bool sendRequest=true)
Adds a new member to a conversation (this will triggers a member event + new message on success)
bool onFileChannelRequest(const std::string &conversationId, const std::string &member, const std::string &fileId, bool verifyShaSum=true) const
Choose if we can accept channel request.
void clearPendingFetch()
Clear not removed fetch.
void reloadRequests()
Reload requests from file.
void onNeedConversationRequest(const std::string &from, const std::string &conversationId)
Called when a peer needs an invite for a conversation (generally after that they received a commit no...
uint32_t loadConversationMessages(const std::string &conversationId, const std::string &fromMessage="", size_t n=0)
Load conversation's messages.
static void saveConvRequestsToPath(const std::filesystem::path &path, const std::map< std::string, ConversationRequest > &conversationsRequests)
std::map< std::string, std::map< std::string, std::string > > convPreferences() const
Retrieve all conversation preferences to sync with other devices.
std::vector< std::string > getConversations() const
Return all conversation's id (including syncing ones)
static void saveConvRequests(const std::string &accountId, const std::map< std::string, ConversationRequest > &conversationsRequests)
void setConversationPreferences(const std::string &conversationId, const std::map< std::string, std::string > &prefs)
Update user's preferences (like color, notifications, etc) to be synced across devices.
bool needsSyncingWith(const std::string &memberUri, const std::string &deviceId) const
Check if we need to share infos with a contact.
std::map< std::string, std::string > getConversationPreferences(const std::string &conversationId, bool includeCreated=false) const
static std::map< std::string, ConversationRequest > convRequests(const std::string &accountId)
std::map< std::string, std::string > conversationInfos(const std::string &conversationId) const
void acceptConversationRequest(const std::string &conversationId, const std::string &deviceId="")
Accept a conversation's request.
std::shared_ptr< SIPCall > call(const std::string &url, const std::vector< libjami::MediaMap > &mediaList, std::function< void(const std::string &, const DeviceId &, const std::shared_ptr< SIPCall > &)> &&cb)
Call the conversation.
bool updateConvForContact(const std::string &uri, const std::string &oldConv, const std::string &newConv)
Replace linked conversation in contact's details.
std::string getOneToOneConversation(const std::string &uri) const noexcept
Get related conversation with member.
void shutdownConnections()
Clear all connection (swarm channels)
void bootstrap(const std::string &convId="")
Bootstrap swarm managers to other peers.
std::string startConversation(ConversationMode mode=ConversationMode::INVITES_ONLY, const dht::InfoHash &otherMember={})
Starts a new conversation.
void fetchNewCommits(const std::string &peer, const std::string &deviceId, const std::string &conversationId, const std::string &commitId)
Launch fetch on new commit.
uint32_t loadConversationUntil(const std::string &conversationId, const std::string &fromMessage, const std::string &to)
void setFetched(const std::string &conversationId, const std::string &deviceId, const std::string &commit)
Notify that a peer fetched a commit.
void sendMessage(const std::string &conversationId, Json::Value &&value, const std::string &replyTo="", bool announce=true, OnCommitCb &&onCommit={}, OnDoneCb &&cb={})
bool isHosting(const std::string &conversationId, const std::string &confId) const
Check if we're hosting a specific conference.
uint32_t loadConversation(const std::string &conversationId, const std::string &fromMessage="", size_t n=0)
void removeConversationMember(const std::string &conversationId, const dht::InfoHash &contactUri, bool isDevice=false)
Remove a member from a conversation (this will trigger a member event + new message on success)
uint32_t countInteractions(const std::string &convId, const std::string &toId, const std::string &fromId, const std::string &authorUri) const
Retrieve the number of interactions from interactionId to HEAD.
static std::map< std::string, ConversationRequest > convRequestsFromPath(const std::filesystem::path &path)
bool downloadFile(const std::string &conversationId, const std::string &interactionId, const std::string &fileId, const std::string &path)
Ask conversation's members to send a file to this device.
std::vector< uint8_t > conversationVCard(const std::string &conversationId) const
static std::map< std::string, ConvInfo > convInfos(const std::string &accountId)
void addCallHistoryMessage(const std::string &uri, uint64_t duration_ms, const std::string &reason)
Add to the related conversation the call history message.
void addGitSocket(std::string_view deviceId, std::string_view convId, const std::shared_ptr< dhtnet::ChannelSocket > &channel)
void clearCache(const std::string &conversationId)
Clear loaded interactions.
void reactToMessage(const std::string &conversationId, const std::string &newBody, const std::string &reactToId)
std::vector< std::map< std::string, std::string > > getConversationMembers(const std::string &conversationId, bool includeBanned=false) const
Get members.
std::shared_ptr< dhtnet::ChannelSocket > gitSocket(std::string_view deviceId, std::string_view convId) const
Return current git socket used for a conversation.
void hostConference(const std::string &conversationId, const std::string &confId, const std::string &callId, const std::vector< libjami::MediaMap > &mediaList={})
uint32_t loadSwarmUntil(const std::string &conversationId, const std::string &fromMessage, const std::string &toMessage)
void onSyncData(const SyncMsg &msg, const std::string &peerId, const std::string &deviceId)
Detect new conversations and request from other devices.
void loadConversations()
Refresh information about conversations.
void addConvInfo(const ConvInfo &info)
static std::map< std::string, ConvInfo > convInfosFromPath(const std::filesystem::path &path)
void loadSingleConversation(const std::string &convId)
bool isBanned(const std::string &convId, const std::string &uri) const
Return if a device or member is banned from a conversation.
std::vector< std::map< std::string, std::string > > getActiveCalls(const std::string &conversationId) const
Return active calls.
void updateConversationInfos(const std::string &conversationId, const std::map< std::string, std::string > &infos, bool sync=true)
Update metadatas from conversations (like title, avatar, etc)
std::shared_ptr< Typers > getTypers(const std::string &convId)
Get Typers object for a conversation.
void cloneConversationFrom(const std::string &conversationId, const std::string &uri, const std::string &oldConvId="")
Clone conversation from a member.
std::string peerFromConversationRequest(const std::string &convId) const
Retrieve author of a conversation request.
void declineConversationRequest(const std::string &conversationId)
Decline a conversation's request.
void onTrustRequest(const std::string &uri, const std::string &conversationId, const std::vector< uint8_t > &payload, time_t received)
Called when detecting a new trust request with linked one to one.
std::shared_ptr< TransferManager > dataTransfer(const std::string &id) const
Returns related transfer manager.
bool removeConversation(const std::string &conversationId)
Remove a conversation, but not the contact.
std::map< std::string, std::map< std::string, std::map< std::string, std::string > > > convMessageStatus() const
static constexpr const char MIME_TYPE_INVITE[]
std::function< void(const std::string &, const std::string &, ChannelCb &&, const std::string &)> NeedSocketCb
dht::PkId DeviceId
static constexpr const char MIME_TYPE_GIT[]
void emitSignal(Args... args)
Definition ring_signal.h:64
std::function< void(bool, const std::string &)> OnDoneCb
std::function< void(const std::string &, const std::string &)> OneToOneRecvCb
std::function< bool(const std::shared_ptr< dhtnet::ChannelSocket > &)> ChannelCb
std::function< void(const std::string &)> OnCommitCb
std::function< void(std::shared_ptr< SyncMsg > &&)> NeedsSyncingCb
std::function< uint64_t(const std::string &, const DeviceId &, std::map< std::string, std::string >, uint64_t)> SengMsgCb
std::map< std::string, std::map< std::string, std::string > > p
std::map< std::string, std::map< std::string, std::string > > ld
std::map< std::string, std::map< std::string, std::map< std::string, std::string > > > ms
std::map< std::string, ConversationRequest > cr
std::map< std::string, ConvInfo > c