Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 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 :
18 : #pragma once
19 :
20 : #include "jamidht/commit_message.h"
21 : #include "jamidht/conversationrepository.h"
22 : #include "conversationrepository.h"
23 : #include "swarm/swarm_protocol.h"
24 : #include "jami/conversation_interface.h"
25 : #include "jamidht/typers.h"
26 : #include "string_utils.h"
27 : #include "timestamp.h"
28 :
29 : #include <json/json.h>
30 : #include <msgpack.hpp>
31 :
32 : #include <chrono>
33 : #include <functional>
34 : #include <string>
35 : #include <vector>
36 : #include <map>
37 : #include <memory>
38 : #include <set>
39 :
40 : #include <asio.hpp>
41 :
42 : namespace dhtnet {
43 : class ChannelSocket;
44 : } // namespace dhtnet
45 :
46 : namespace jami {
47 :
48 : namespace ConversationMapKeys {
49 : static constexpr const char* ID {"id"};
50 : static constexpr const char* CREATED {"created"};
51 : static constexpr const char* REMOVED {"removed"};
52 : static constexpr const char* ERASED {"erased"};
53 : static constexpr const char* MEMBERS {"members"};
54 : static constexpr const char* LAST_DISPLAYED {"lastDisplayed"};
55 : static constexpr const char* RECEIVED {"received"};
56 : static constexpr const char* DECLINED {"declined"};
57 : static constexpr const char* FROM {"from"};
58 : static constexpr const char* CONVERSATIONID {"conversationId"};
59 : static constexpr const char* METADATAS {"metadatas"};
60 : static constexpr const char* MODE {"mode"};
61 : // Millisecond-resolution variants. Legacy keys above keep carrying seconds
62 : // so that older devices (which ignore unknown keys) remain compatible.
63 : static constexpr const char* CREATED_MS {"createdMs"};
64 : static constexpr const char* REMOVED_MS {"removedMs"};
65 : static constexpr const char* ERASED_MS {"erasedMs"};
66 : static constexpr const char* RECEIVED_MS {"receivedMs"};
67 : static constexpr const char* DECLINED_MS {"declinedMs"};
68 : } // namespace ConversationMapKeys
69 :
70 : namespace ConversationDirectories {
71 : static constexpr std::string_view PREFERENCES {"preferences"};
72 : static constexpr std::string_view STATUS {"status"};
73 : static constexpr std::string_view SENDING {"sending"};
74 : static constexpr std::string_view FETCHED {"fetched"};
75 : static constexpr std::string_view ACTIVE_CALLS {"activeCalls"};
76 : static constexpr std::string_view HOSTED_CALLS {"hostedCalls"};
77 : static constexpr std::string_view CACHED {"cached"};
78 : } // namespace ConversationDirectories
79 :
80 : namespace ConversationPreferences {
81 : static constexpr const char* HOST_CONFERENCES = "hostConferences";
82 : }
83 :
84 : class JamiAccount;
85 : class ConversationRepository;
86 : class TransferManager;
87 : enum class ConversationMode;
88 :
89 : /**
90 : * A ConversationRequest is a request which corresponds to a trust request, but for conversations
91 : * It's signed by the sender and contains the members list, the conversationId, and the metadatas
92 : * such as the conversation's vcard, etc. (TODO determine)
93 : * Transmitted via the UDP DHT
94 : */
95 : struct ConversationRequest
96 : {
97 : std::string conversationId;
98 : std::string from;
99 : std::map<std::string, std::string> metadatas;
100 :
101 : TimePoint received {};
102 : TimePoint declined {};
103 :
104 324 : ConversationRequest() = default;
105 : ConversationRequest(const Json::Value& json);
106 :
107 : Json::Value toJson() const;
108 : std::map<std::string, std::string> toMap() const;
109 :
110 : bool operator==(const ConversationRequest& o) const
111 : {
112 : auto m = toMap();
113 : auto om = o.toMap();
114 : return m.size() == om.size() && std::equal(m.begin(), m.end(), om.begin());
115 : }
116 :
117 459 : bool isOneToOne() const
118 : {
119 : try {
120 1377 : return metadatas.at("mode") == "0";
121 70 : } catch (...) {
122 70 : }
123 70 : return true;
124 : }
125 :
126 169 : ConversationMode mode() const
127 : {
128 : try {
129 507 : return to_enum<ConversationMode>(metadatas.at("mode"));
130 50 : } catch (...) {
131 50 : }
132 50 : return ConversationMode::ONE_TO_ONE;
133 : }
134 :
135 : // Hand-written msgpack serialization (replaces MSGPACK_DEFINE_MAP) to emit
136 : // dual keys: legacy seconds (received/declined) + milliseconds (receivedMs/declinedMs).
137 : // Readers prefer the ms keys and fall back to seconds * 1000.
138 : template<typename Packer>
139 232 : void msgpack_pack(Packer& pk) const
140 : {
141 232 : int64_t receivedSec = toSecondsSinceEpoch(received);
142 232 : int64_t declinedSec = toSecondsSinceEpoch(declined);
143 232 : int64_t receivedMs = toMillisecondsSinceEpoch(received);
144 232 : int64_t declinedMs = toMillisecondsSinceEpoch(declined);
145 : msgpack::type::make_define_map(ConversationMapKeys::FROM,
146 232 : from,
147 : ConversationMapKeys::CONVERSATIONID,
148 232 : conversationId,
149 : ConversationMapKeys::METADATAS,
150 232 : metadatas,
151 : ConversationMapKeys::RECEIVED,
152 : receivedSec,
153 : ConversationMapKeys::DECLINED,
154 : declinedSec,
155 : ConversationMapKeys::RECEIVED_MS,
156 : receivedMs,
157 : ConversationMapKeys::DECLINED_MS,
158 : declinedMs)
159 232 : .msgpack_pack(pk);
160 232 : }
161 : void msgpack_unpack(const msgpack::object& o);
162 : void msgpack_object(msgpack::object* o, msgpack::zone& z) const;
163 : };
164 :
165 : struct ConvInfo
166 : {
167 : std::string id {};
168 : TimePoint created {};
169 : TimePoint removed {};
170 : TimePoint erased {};
171 : std::set<std::string> members;
172 : std::string lastDisplayed {};
173 : ConversationMode mode {0};
174 :
175 630 : ConvInfo() = default;
176 30 : ConvInfo(const ConvInfo&) = default;
177 0 : ConvInfo(ConvInfo&&) = default;
178 539 : ConvInfo(const std::string& id)
179 539 : : id(id) {};
180 : explicit ConvInfo(const Json::Value& json);
181 :
182 17078 : bool isRemoved() const { return removed >= created; }
183 :
184 2823 : ConvInfo& operator=(const ConvInfo&) = default;
185 181 : ConvInfo& operator=(ConvInfo&&) = default;
186 :
187 : Json::Value toJson() const;
188 :
189 : // Hand-written msgpack serialization (replaces MSGPACK_DEFINE_MAP) to emit
190 : // dual keys: legacy seconds (created/removed/erased) + milliseconds
191 : // (createdMs/removedMs/erasedMs). Readers prefer the ms keys and fall back
192 : // to seconds * 1000.
193 : template<typename Packer>
194 2993 : void msgpack_pack(Packer& pk) const
195 : {
196 2993 : int64_t createdSec = toSecondsSinceEpoch(created);
197 2993 : int64_t removedSec = toSecondsSinceEpoch(removed);
198 2993 : int64_t erasedSec = toSecondsSinceEpoch(erased);
199 2992 : int64_t createdMs = toMillisecondsSinceEpoch(created);
200 2992 : int64_t removedMs = toMillisecondsSinceEpoch(removed);
201 2993 : int64_t erasedMs = toMillisecondsSinceEpoch(erased);
202 : msgpack::type::make_define_map(ConversationMapKeys::ID,
203 2993 : id,
204 : ConversationMapKeys::CREATED,
205 : createdSec,
206 : ConversationMapKeys::REMOVED,
207 : removedSec,
208 : ConversationMapKeys::ERASED,
209 : erasedSec,
210 : ConversationMapKeys::MEMBERS,
211 2993 : members,
212 : ConversationMapKeys::LAST_DISPLAYED,
213 2993 : lastDisplayed,
214 : ConversationMapKeys::MODE,
215 2993 : mode,
216 : ConversationMapKeys::CREATED_MS,
217 : createdMs,
218 : ConversationMapKeys::REMOVED_MS,
219 : removedMs,
220 : ConversationMapKeys::ERASED_MS,
221 : erasedMs)
222 2993 : .msgpack_pack(pk);
223 2993 : }
224 : void msgpack_unpack(const msgpack::object& o);
225 : void msgpack_object(msgpack::object* o, msgpack::zone& z) const;
226 : };
227 :
228 : using OnPullCb = std::function<void(bool fetchOk)>;
229 : using OnLoadMessages = std::function<void(std::vector<libjami::SwarmMessage>&& messages)>;
230 : using OnCommitCb = std::function<void(const std::string&)>;
231 : using OnDoneCb = std::function<void(bool, const std::string&)>;
232 : using OnMembersChanged = std::function<void(const std::set<std::string>&)>;
233 : using DeviceId = dht::PkId;
234 : using GitSocketList = std::map<DeviceId, std::shared_ptr<dhtnet::ChannelSocket>>;
235 : using ChannelCb = std::function<bool(const std::shared_ptr<dhtnet::ChannelSocket>&)>;
236 : using NeedSocketCb
237 : = std::function<void(const std::string&, const std::string&, ChannelCb&&, const std::string&, bool noNewSocket)>;
238 :
239 : class Conversation : public std::enable_shared_from_this<Conversation>
240 : {
241 : public:
242 : Conversation(const std::shared_ptr<JamiAccount>& account,
243 : ConversationMode mode,
244 : const std::string& otherMember = "");
245 : Conversation(const std::shared_ptr<JamiAccount>& account, const std::string& conversationId = "");
246 : Conversation(const std::shared_ptr<JamiAccount>& account,
247 : const std::string& remoteDevice,
248 : const std::string& conversationId);
249 : ~Conversation();
250 :
251 : /**
252 : * Print the state of the DRT linked to the conversation
253 : */
254 : void monitor();
255 :
256 : #ifdef LIBJAMI_TEST
257 : enum class BootstrapStatus { FAILED, FALLBACK, SUCCESS };
258 : /**
259 : * Used by the tests to get whenever the DRT is connected/disconnected
260 : */
261 : void onBootstrapStatus(const std::function<void(std::string, BootstrapStatus)>& cb);
262 :
263 : std::vector<libjami::SwarmMessage> loadMessagesSync(const LogOptions& options);
264 : void announce(const std::vector<std::map<std::string, std::string>>& commits, bool commitFromSelf = false);
265 : void announce(const std::string& commitId, bool commitFromSelf = false);
266 : #endif
267 :
268 : /**
269 : * Bootstrap swarm manager to other peers
270 : * @param onBootstrapped Callback called when connection is established successfully
271 : * @param knownDevices Optional list of live devices to seed the DRT with.
272 : * Normally empty: candidates are fed by the per-device
273 : * presence monitoring through addKnownDevices().
274 : */
275 : void bootstrap(std::function<void()> onBootstrapped, const std::vector<DeviceId>& knownDevices = {});
276 :
277 : /**
278 : * Add known devices to the swarm manager
279 : * @param devices
280 : * @param memberUri
281 : */
282 : void addKnownDevices(const std::vector<DeviceId>& devices, const std::string& memberUri);
283 :
284 : /**
285 : * Proactively connect a device in the swarm, bypassing DRT bucket checks.
286 : * Used when a TCP link to the device already exists.
287 : * @param deviceId
288 : */
289 : void connectNode(const DeviceId& deviceId);
290 :
291 : /**
292 : * Refresh active calls.
293 : * @note: If the host crash during a call, when initializing, we need to update
294 : * and commit all the crashed calls
295 : * @return Commits added
296 : */
297 : std::vector<std::string> commitsEndedCalls();
298 :
299 : void onMembersChanged(OnMembersChanged&& cb);
300 :
301 : /**
302 : * Set the callback that will be called whenever a new socket will be needed
303 : * @param cb
304 : */
305 : void onNeedSocket(NeedSocketCb cb);
306 : /**
307 : * Add swarm connection to the DRT
308 : * @param channel Related channel
309 : */
310 : void addSwarmChannel(std::shared_ptr<dhtnet::ChannelSocket> channel);
311 :
312 : /**
313 : * Get conversation's id
314 : * @return conversation Id
315 : */
316 : std::string id() const;
317 :
318 : // Member management
319 : /**
320 : * Add conversation member
321 : * @param uri Member to add
322 : * @param cb On done cb
323 : */
324 : void addMember(const std::string& contactUri, const OnDoneCb& cb = {});
325 : void removeMember(const std::string& contactUri, bool isDevice, const OnDoneCb& cb = {});
326 : /**
327 : * @param includeInvited If we want invited members
328 : * @param includeLeft If we want left members
329 : * @param includeBanned If we want banned members
330 : * @return a vector of member details:
331 : * {
332 : * "uri":"xxx",
333 : * "role":"member/admin/invited",
334 : * "lastDisplayed":"id"
335 : * ...
336 : * }
337 : */
338 : std::vector<std::map<std::string, std::string>> getMembers(bool includeInvited = false,
339 : bool includeLeft = false,
340 : bool includeBanned = false) const;
341 :
342 : /**
343 : * @param filter If we want to remove one member
344 : * @param filteredRoles If we want to ignore some roles
345 : * @return members' uris
346 : */
347 : std::set<std::string> memberUris(std::string_view filter = {},
348 : const std::set<MemberRole>& filteredRoles = {MemberRole::INVITED,
349 : MemberRole::LEFT,
350 : MemberRole::BANNED}) const;
351 :
352 : std::vector<std::map<std::string, std::string>> getTrackedMembers() const;
353 :
354 : /**
355 : * Get peers to sync with. This is mostly managed by the DRT
356 : * @return some mobile nodes and all connected nodes
357 : */
358 : std::vector<NodeId> peersToSyncWith() const;
359 : /**
360 : * Check if we're at least connected to one node
361 : * @return if the DRT is connected
362 : */
363 : bool isBootstrapped() const;
364 : /**
365 : * Retrieve the uri from a deviceId
366 : * @note used by swarm manager (peersToSyncWith)
367 : * @param deviceId
368 : * @return corresponding issuer
369 : */
370 : std::string uriFromDevice(const std::string& deviceId) const;
371 :
372 : /**
373 : * Join a conversation
374 : * @return commit id to send
375 : */
376 : std::string join();
377 :
378 : /**
379 : * Test if an URI is a member
380 : * @param uri URI to test
381 : * @return true if uri is a member
382 : */
383 : bool isMember(const std::string& uri, bool includeInvited = false) const;
384 : bool isMemberBanned(const std::string& uri) const;
385 : bool isDeviceBanned(const std::string& deviceId) const;
386 :
387 : /**
388 : * Check if a device is authorized to clone or interact with the conversation.
389 : * Assumption: the deviceId must already be a confirmed device of the user.
390 : * @param uri URI of the user
391 : * @param deviceId Device id to check
392 : * @param includeInvited If true, consider invited members as authorized.
393 : */
394 : bool isPeerAuthorized(const std::string& uri, const std::string& deviceId, bool includeInvited = false) const;
395 :
396 : void createCommit(CommitMessage&& message, OnCommitCb&& onCommit = {}, OnDoneCb&& cb = {});
397 :
398 : /**
399 : * Get a range of messages
400 : * @param cb The callback when loaded
401 : * @param options The log options
402 : */
403 : void loadMessages(const OnLoadMessages& cb, const LogOptions& options);
404 : /**
405 : * For every loaded TEXT message that has no bodyOverwrite in pluginData, runs the plugin
406 : * ChatServicesManager transform to obtain one. If the plugin produces a bodyOverwrite,
407 : * stores it in pluginData and emits SwarmMessageUpdated for the affected message
408 : * (edition commits signal the original message; originals signal themselves).
409 : * No-op when no plugin chat handlers are registered.
410 : */
411 : void loadMissingBodyOverwrites() const;
412 : /**
413 : * Drops all bodyOverwrite entries from the loaded message history, then calls
414 : * loadMissingBodyOverwrites() to re-derive them from scratch via the plugin transform.
415 : * Use when plugin chat handlers are reloaded or their transform logic has changed.
416 : */
417 : void reloadBodyOverwriteMessages() const;
418 : /**
419 : * Stores or clears the plugin-provided bodyOverwrite for a single message.
420 : * An empty bodyOverwrite sets the entry to "" (marks the message as processed with no
421 : * overwrite, preventing reprocessing); a non-empty value replaces it.
422 : * If messageId refers to an edition commit, SwarmMessageUpdated is emitted for the
423 : * original message (the one clients display); otherwise it is emitted for messageId itself.
424 : * @param messageId Id of the message (original or edition commit) to update.
425 : * @param bodyOverwrite Plugin-transformed body text, or empty to clear the override.
426 : */
427 : void updateMessageBodyOverwrite(const std::string& messageId, const std::string& bodyOverwrite) const;
428 : /**
429 : * Removes all bodyOverwrite entries from every message in the loaded history and emits
430 : * SwarmMessageUpdated for each affected message so clients revert to the original
431 : * body. Edition commits are resolved to their original message before signalling.
432 : */
433 : void clearBodyOverwrites() const;
434 : /**
435 : * Clear all cached messages
436 : */
437 : void clearCache();
438 : /**
439 : * Check if a commit exists in the repository
440 : * @param commitId The commit id to check
441 : * @return true if the commit was found, false if not or if an error occurred
442 : */
443 : bool hasCommit(const std::string& commitId) const;
444 : /**
445 : * Retrieve one commit
446 : * @param commitId
447 : * @return The commit if found
448 : */
449 : std::optional<ConversationCommit> getCommit(const std::string& commitId) const;
450 : /**
451 : * Get last commit id
452 : * @return last commit id
453 : */
454 : std::string lastCommitId() const;
455 :
456 : /**
457 : * Fetch and merge from peer
458 : * @param deviceId Peer device
459 : * @param cb On pulled callback
460 : * @param commitId Commit id that triggered this fetch
461 : * @return true if callback will be called later
462 : */
463 : bool pull(const std::string& deviceId, OnPullCb&& cb, std::string commitId = "");
464 : /**
465 : * Fetch new commits and re-ask for waiting files
466 : * @param member
467 : * @param deviceId
468 : * @param cb cf pull()
469 : * @param commitId cf pull()
470 : */
471 : void sync(const std::string& member, const std::string& deviceId, OnPullCb&& cb, std::string commitId = "");
472 :
473 : /**
474 : * Generate an invitation to send to new contacts
475 : * @return the invite to send
476 : */
477 : std::map<std::string, std::string> generateInvitation() const;
478 :
479 : /**
480 : * Leave a conversation
481 : * @return commit id to send
482 : */
483 : std::string leave();
484 :
485 : /**
486 : * Set a conversation as removing (when loading convInfo and still not sync)
487 : * @todo: not a big fan to see this here. can be set in the constructor
488 : * cause it's used by jamiaccount when loading conversations
489 : */
490 : void setRemovingFlag();
491 :
492 : /**
493 : * Check if we are removing the conversation
494 : * @return true if left the room
495 : */
496 : bool isRemoving();
497 :
498 : /**
499 : * Erase all related datas
500 : */
501 : void erase();
502 :
503 : /**
504 : * Get conversation's mode
505 : * @return the mode
506 : */
507 : ConversationMode mode() const;
508 :
509 : /**
510 : * One to one util, get initial members
511 : * @return initial members
512 : */
513 : std::vector<std::string> getInitialMembers() const;
514 : bool isInitialMember(const std::string& uri) const;
515 :
516 : /**
517 : * Change repository's infos
518 : * @param map New infos (supported keys: title, description, avatar)
519 : * @param cb On commited
520 : */
521 : void updateInfos(const std::map<std::string, std::string>& map, const OnDoneCb& cb = {});
522 :
523 : /**
524 : * Change user's preferences
525 : * @param map New preferences
526 : */
527 : void updatePreferences(const std::map<std::string, std::string>& map);
528 :
529 : /**
530 : * Retrieve current infos (title, description, avatar, mode)
531 : * @return infos
532 : */
533 : std::map<std::string, std::string> infos() const;
534 : /**
535 : * Retrieve current preferences (color, notification, etc)
536 : * @param includeLastModified If we want to know when the preferences were modified
537 : * @return preferences
538 : */
539 : std::map<std::string, std::string> preferences(bool includeLastModified) const;
540 : std::vector<uint8_t> vCard() const;
541 :
542 : /////// File transfer
543 :
544 : /**
545 : * Access to transfer manager
546 : */
547 : std::shared_ptr<TransferManager> dataTransfer() const;
548 :
549 : /**
550 : * Choose if we can accept channel request
551 : * @param member member to check
552 : * @param fileId file transfer to check (needs to be waiting)
553 : * @param verifyShaSum for debug only
554 : * @return if we accept the channel request
555 : */
556 : bool onFileChannelRequest(const std::string& member,
557 : const std::string& fileId,
558 : std::filesystem::path& path,
559 : std::string& sha3sum) const;
560 : /**
561 : * Adds a file to the waiting list and ask members
562 : * @param interactionId Related interaction id
563 : * @param fileId Related id
564 : * @param path Destination
565 : * @param member Member if we know from who to pull file
566 : * @param deviceId Device if we know from who to pull file
567 : * @return id of the file
568 : */
569 : bool downloadFile(const std::string& interactionId,
570 : const std::string& fileId,
571 : const std::string& path,
572 : const std::string& member = "",
573 : const std::string& deviceId = "");
574 :
575 : /**
576 : * Reset fetched information
577 : */
578 : void clearFetched();
579 : /**
580 : * Store information about who fetch or not. This simplify sync (sync when a device without the
581 : * last fetch is detected)
582 : * @param deviceId
583 : * @param commitId
584 : */
585 : void hasFetched(const std::string& deviceId, const std::string& commitId);
586 :
587 : /**
588 : * Store last read commit (returned in getMembers)
589 : * @param uri Of the member
590 : * @param interactionId Last interaction displayed
591 : * @return if updated
592 : */
593 : bool setMessageDisplayed(const std::string& uri, const std::string& interactionId);
594 : /**
595 : * Retrieve last displayed and fetch status per member
596 : * @return A map with the following structure:
597 : * {uri, {
598 : * {"fetch", "commitId"},
599 : * {"fetched_ts", "timestamp"},
600 : * {"read", "commitId"},
601 : * {"read_ts", "timestamp"}
602 : * }
603 : * }
604 : */
605 : std::map<std::string, std::map<std::string, std::string>> messageStatus() const;
606 : /**
607 : * Update fetch/read status
608 : * @param messageStatus A map with the following structure:
609 : * {uri, {
610 : * {"fetch", "commitId"},
611 : * {"fetched_ts", "timestamp"},
612 : * {"read", "commitId"},
613 : * {"read_ts", "timestamp"}
614 : * }
615 : * }
616 : */
617 : void updateMessageStatus(const std::map<std::string, std::map<std::string, std::string>>& messageStatus);
618 : void onMessageStatusChanged(
619 : const std::function<void(const std::map<std::string, std::map<std::string, std::string>>&)>& cb);
620 : /**
621 : * Retrieve how many interactions there is from HEAD to interactionId
622 : * @param toId "" for getting the whole history
623 : * @param fromId "" => HEAD
624 : * @param authorURI author to stop counting
625 : * @return number of interactions since interactionId
626 : */
627 : uint32_t countInteractions(const std::string& toId,
628 : const std::string& fromId = "",
629 : const std::string& authorUri = "") const;
630 : /**
631 : * Search in the conversation via a filter
632 : * @param req Id of the request
633 : * @param filter Parameters for the search
634 : * @param flag To check when search is finished
635 : * @note triggers messagesFound
636 : */
637 : void search(uint32_t req, const Filter& filter, const std::shared_ptr<std::atomic_int>& flag) const;
638 : /**
639 : * Host a conference in the conversation
640 : * @note the message must have "confId"
641 : * @note Update hostedCalls_ and commit in the conversation
642 : * @param message message to commit
643 : * @param cb callback triggered when committed
644 : */
645 : void hostConference(CommitMessage&& message, OnDoneCb&& cb = {});
646 : /**
647 : * Announce the end of a call
648 : * @note the message must have "confId"
649 : * @note called when conference is finished
650 : * @param message message to commit
651 : * @param cb callback triggered when committed
652 : */
653 : void removeActiveConference(CommitMessage&& message, OnDoneCb&& cb = {});
654 : /**
655 : * Check if we're currently hosting this conference
656 : * @param confId
657 : * @return true if hosting
658 : */
659 : bool isHosting(const std::string& confId) const;
660 : /**
661 : * Return current detected calls
662 : * @return a vector of map with the following keys: "id", "uri", "device"
663 : */
664 : std::vector<std::map<std::string, std::string>> currentCalls() const;
665 :
666 : /**
667 : * Git operations will need a ChannelSocket for cloning/fetching commits
668 : * Because libgit2 is a C library, we store the pointer in the corresponding conversation
669 : * and the GitTransport will inject to libgit2 whenever needed
670 : */
671 : std::shared_ptr<dhtnet::ChannelSocket> gitSocket(const DeviceId& deviceId) const;
672 : void addGitSocket(const DeviceId& deviceId, const std::shared_ptr<dhtnet::ChannelSocket>& socket);
673 : void removeGitSocket(const DeviceId& deviceId);
674 :
675 : /**
676 : * Stop SwarmManager, bootstrap and gitSockets
677 : */
678 : void shutdownConnections();
679 :
680 : /**
681 : * If we change from one network to one another, we will need to update the state of the connections
682 : */
683 : void connectivityChanged();
684 :
685 : /**
686 : * @return getAllNodes() Nodes that are linked to the conversation
687 : */
688 : std::vector<jami::DeviceId> getDeviceIdList() const;
689 :
690 : /**
691 : * Get Typers object
692 : * @return Typers object
693 : */
694 : std::shared_ptr<Typers> typers() const;
695 :
696 : /**
697 : * Get connectivity information for the conversation
698 : * @return map of connectivity info
699 : */
700 : std::vector<std::map<std::string, std::string>> getConnectivity() const;
701 :
702 : private:
703 : std::shared_ptr<Conversation> shared() { return std::static_pointer_cast<Conversation>(shared_from_this()); }
704 : std::shared_ptr<Conversation const> shared() const
705 : {
706 : return std::static_pointer_cast<Conversation const>(shared_from_this());
707 : }
708 3640 : std::weak_ptr<Conversation> weak() { return std::static_pointer_cast<Conversation>(shared_from_this()); }
709 4 : std::weak_ptr<Conversation const> weak() const
710 : {
711 4 : return std::static_pointer_cast<Conversation const>(shared_from_this());
712 : }
713 :
714 : // Private because of weak()
715 : class Impl;
716 : std::unique_ptr<Impl> pimpl_;
717 : };
718 :
719 : } // namespace jami
|