Ring Daemon
Loading...
Searching...
No Matches
conversationrepository.h
Go to the documentation of this file.
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#pragma once
18#include "def.h"
19#include "vcard.h"
20#include "git_def.h"
21
22#include <opendht/default_types.h>
23
24#include <optional>
25#include <memory>
26#include <string>
27#include <vector>
28
29namespace jami {
30
31using DeviceId = dht::PkId;
32
33constexpr auto EFETCH = 1;
34constexpr auto EINVALIDMODE = 2;
35constexpr auto EVALIDFETCH = 3;
36constexpr auto EUNAUTHORIZED = 4;
37constexpr auto ECOMMIT = 5;
38
39class JamiAccount;
40
42{
43 std::string from {};
44 std::string to {};
45 uint64_t nbOfCommits {0}; // maximum number of commits wanted
46 bool skipMerge {false}; // Do not include merge commits in the log. Used by the module to get
47 // last interaction without potential merges
48 bool includeTo {false}; // If we want or not the "to" commit [from-to] or [from-to)
49 bool fastLog {false}; // Do not parse content, used mostly to count
50 bool logIfNotFound {true}; // Add a warning in the log if commit is not found
51
52 std::string authorUri {}; // filter commits from author
53};
54
55struct Filter
56{
57 std::string author;
58 std::string lastId;
59 std::string regexSearch;
60 std::string type;
64 bool caseSensitive {false};
65};
66
68{
69 std::string name {};
70 std::string email {};
71};
72
74
76{
77 std::string id {};
78 std::vector<std::string> parents {};
80 std::vector<uint8_t> signed_content {};
81 std::vector<uint8_t> signature {};
82 std::string commit_msg {};
83 std::string linearized_parent {};
85};
86
87enum class MemberRole { ADMIN = 0, MEMBER, INVITED, BANNED, LEFT };
88
89namespace MemberPath {
90
91static const std::filesystem::path ADMINS {"admins"};
92static const std::filesystem::path MEMBERS {"members"};
93static const std::filesystem::path INVITED {"invited"};
94static const std::filesystem::path BANNED {"banned"};
95static const std::filesystem::path DEVICES {"devices"};
96
97} // namespace MemberPath
98
100{
101 std::string uri;
103
104 std::map<std::string, std::string> map() const
105 {
106 std::string rolestr;
107 if (role == MemberRole::ADMIN) {
108 rolestr = "admin";
109 } else if (role == MemberRole::MEMBER) {
110 rolestr = "member";
111 } else if (role == MemberRole::INVITED) {
112 rolestr = "invited";
113 } else if (role == MemberRole::BANNED) {
114 rolestr = "banned";
115 } else if (role == MemberRole::LEFT) {
116 rolestr = "left"; // For one to one
117 }
118
119 return {{"uri", uri}, {"role", rolestr}};
120 }
122};
123
124enum class CallbackResult { Skip, Break, Ok };
125
126using PreConditionCb = std::function<CallbackResult(const std::string&, const GitAuthor&, const GitCommit&)>;
127using PostConditionCb = std::function<bool(const std::string&, const GitAuthor&, ConversationCommit&)>;
128using OnMembersChanged = std::function<void(const std::set<std::string>&)>;
129
134{
135public:
136#ifdef LIBJAMI_TEST
137 static bool DISABLE_RESET; // Some tests inject bad files so resetHard() will break the test
138
139 // If true, clone and fetch operations will be performed directly using the target repo's path,
140 // avoiding the need for setting up a GitServer and a DHTNet connection.
141 static bool FETCH_FROM_LOCAL_REPOS;
142#endif
150 static LIBJAMI_TEST_EXPORT std::unique_ptr<ConversationRepository> createConversation(
151 const std::shared_ptr<JamiAccount>& account,
152 ConversationMode mode = ConversationMode::INVITES_ONLY,
153 const std::string& otherMember = "");
154
162 static LIBJAMI_TEST_EXPORT std::pair<std::unique_ptr<ConversationRepository>, std::vector<ConversationCommit>>
163 cloneConversation(const std::shared_ptr<JamiAccount>& account,
164 const std::string& deviceId,
165 const std::string& conversationId);
166
172 ConversationRepository(const std::shared_ptr<JamiAccount>& account, const std::string& id);
174
180 std::string addMember(const std::string& uri);
181
189 bool fetch(const std::string& remoteDeviceId);
190
197 std::vector<std::map<std::string, std::string>> mergeHistory(
198 const std::string& uri, std::function<void(const std::string&)>&& disconnectFromPeerCb = {});
199
206 std::string remoteHead(const std::string& remoteDeviceId, const std::string& branch = "main") const;
207
211 const std::string& id() const;
212
219 std::string commitMessage(const std::string& msg, bool verifyDevice = true);
220
221 std::vector<std::string> commitMessages(const std::vector<std::string>& msgs);
222
229 std::string amend(const std::string& id, const std::string& msg);
230
235 std::vector<ConversationCommit> log(const LogOptions& options = {}) const;
236 void log(PreConditionCb&& preCondition,
237 std::function<void(ConversationCommit&&)>&& emplaceCb,
238 PostConditionCb&& postCondition,
239 const std::string& from = "",
240 bool logIfNotFound = true) const;
241
247 bool hasCommit(const std::string& commitId) const;
248 std::optional<ConversationCommit> getCommit(const std::string& commitId) const;
249
254 std::optional<std::string> linearizedParent(const std::string& commitId) const;
255
263 std::pair<bool, std::string> merge(const std::string& merge_id, bool force = false);
264
272 std::string diffStats(const std::string& newId, const std::string& oldId = "") const;
273
279 static std::vector<std::string> changedFiles(std::string_view diffStats);
280
285 std::string join();
286
291 std::string leave();
292
296 void erase();
297
302 ConversationMode mode() const;
303
316 std::string voteKick(const std::string& uri, const std::string& type);
323 std::string voteUnban(const std::string& uri, const std::string_view type);
331 std::string resolveVote(const std::string& uri, const std::string_view type, const std::string& voteType);
332
338 std::pair<std::vector<ConversationCommit>, bool> validFetch(const std::string& remoteDevice) const;
339
344 std::pair<std::vector<ConversationCommit>, bool> validClone() const;
345
351 bool isValidUserAtCommit(const std::string& userDevice,
352 const std::string& commitId,
353 const git_buf& sig,
354 const git_buf& sig_data) const;
355
360 bool validCommits(const std::vector<ConversationCommit>& commitsToValidate) const;
361
366 void removeBranchWith(const std::string& remoteDevice);
367
372 std::vector<std::string> getInitialMembers() const;
373
378 std::vector<ConversationMember> members() const;
379
385 std::map<std::string, std::vector<DeviceId>> devices(bool ignoreExpired = true) const;
386
392 std::set<std::string> memberUris(std::string_view filter, const std::set<MemberRole>& filteredRoles) const;
393
397 void refreshMembers() const;
398
399 void onMembersChanged(OnMembersChanged&& cb);
400
406 void pinCertificates(bool blocking = false);
413 std::string uriFromDevice(const std::string& deviceId) const;
414
420 std::string updateInfos(const std::map<std::string, std::string>& map);
421
426 std::map<std::string, std::string> infos() const;
427 static std::map<std::string, std::string> infosFromVCard(vCard::utils::VCardData&& details);
428
432 std::vector<std::map<std::string, std::string>> convCommitsToMap(
433 const std::vector<ConversationCommit>& commits) const;
434 std::optional<std::map<std::string, std::string>> convCommitToMap(const ConversationCommit& commit) const;
435
439 std::string getHead() const;
440
441private:
442 ConversationRepository() = delete;
443 class Impl;
444 std::unique_ptr<Impl> pimpl_;
445};
446
447} // namespace jami
This class gives access to the git repository that represents the conversation.
std::optional< std::string > linearizedParent(const std::string &commitId) const
Get parent via topological + date sort in branch main of a commit.
Ring Account is build on top of SIPAccountBase and uses DHT to handle call connectivity.
Definition jamiaccount.h:93
MSGPACK_ADD_ENUM(jami::MemberRole)
#define LIBJAMI_TEST_EXPORT
Definition def.h:49
static const std::filesystem::path DEVICES
static const std::filesystem::path INVITED
static const std::filesystem::path BANNED
static const std::filesystem::path ADMINS
static const std::filesystem::path MEMBERS
std::map< std::string, std::string, std::less<> > VCardData
Definition vcard.h:89
dht::PkId DeviceId
void emitSignal(Args... args)
Definition jami_signal.h:64
constexpr auto ECOMMIT
std::function< bool(const std::string &, const GitAuthor &, ConversationCommit &)> PostConditionCb
std::unique_ptr< git_commit, GitCommitDeleter > GitCommit
Definition git_def.h:46
constexpr auto EINVALIDMODE
constexpr auto EVALIDFETCH
constexpr auto EUNAUTHORIZED
std::function< CallbackResult(const std::string &, const GitAuthor &, const GitCommit &)> PreConditionCb
constexpr auto EFETCH
std::function< void(const std::set< std::string > &)> OnMembersChanged
std::vector< uint8_t > signed_content
std::vector< std::string > parents
std::vector< uint8_t > signature
std::map< std::string, std::string > map() const