de_mls/conversation/
query.rs1use crate::{
4 ConsensusPlugin, Conversation, ConversationError, ConversationState, MemberRole,
5 PeerScoringPlugin, StewardListPlugin, mls_crypto::MlsService,
6 protos::de_mls::messages::v1::ConversationUpdateRequest,
7};
8
9impl<C, Sc, St> Conversation<C, Sc, St>
10where
11 C: ConsensusPlugin,
12 Sc: PeerScoringPlugin,
13 St: StewardListPlugin,
14{
15 pub fn state(&self) -> ConversationState {
17 self.current_state()
18 }
19
20 pub fn id(&self) -> &str {
23 &self.conversation_id
24 }
25
26 pub fn member_id_bytes(&self) -> &[u8] {
28 &self.self_member_id
29 }
30
31 pub fn app_id(&self) -> &[u8] {
34 &self.app_id
35 }
36
37 pub fn epoch_and_retry(&self) -> Result<(u64, u32), ConversationError> {
40 let epoch = self.mls().current_epoch()?;
41 Ok((epoch, self.services.steward_list.next_retry_round()))
42 }
43
44 pub fn pending_update_count(&self) -> usize {
48 self.queues.pending_update_count()
49 }
50
51 pub fn freeze_candidate_count(&self) -> (usize, usize) {
54 let received = self.queues.freeze_candidate_count();
55 let expected = self
56 .services
57 .steward_list
58 .current_list()
59 .map(|l| l.len())
60 .unwrap_or(0);
61 (received, expected)
62 }
63
64 pub fn is_steward(&self) -> bool {
65 self.services.steward_list.is_steward(&self.self_member_id)
66 }
67
68 pub fn is_epoch_steward(&self) -> Result<bool, ConversationError> {
76 let mls = self.mls();
77 let epoch = mls.current_epoch()?;
78 let members = mls.members()?;
79 let eligible = self.queues.steward_eligibility(&members);
80 let (epoch_steward, _backup) = self
81 .services
82 .steward_list
83 .epoch_and_backup(epoch, &eligible);
84 Ok(epoch_steward == Some(self.self_member_id.as_ref()))
85 }
86
87 pub fn members(&self) -> Result<Vec<Vec<u8>>, ConversationError> {
90 Ok(self.mls().members()?)
91 }
92
93 pub fn member_scores(&self) -> Vec<(Vec<u8>, i64)> {
94 self.services.scoring.all_members_with_scores()
95 }
96
97 pub fn member_score(&self, member_id: &[u8]) -> Option<i64> {
98 self.services.scoring.score_for(member_id)
99 }
100
101 pub fn pending_leave_member_ids(&self) -> Result<Vec<Vec<u8>>, ConversationError> {
104 let members = self.mls().members()?;
105 Ok(members
106 .into_iter()
107 .filter(|id| self.queues.is_pending_self_leave(id))
108 .collect())
109 }
110
111 pub fn member_roles(&self) -> Result<Vec<(Vec<u8>, MemberRole)>, ConversationError> {
114 let mls = self.mls();
115 let epoch = mls.current_epoch()?;
116 let members = mls.members()?;
117
118 let eligible = self.queues.steward_eligibility(&members);
119 let (live_epoch, live_backup) = self
120 .services
121 .steward_list
122 .epoch_and_backup(epoch, &eligible);
123 let live_epoch = live_epoch.map(|s| s.to_vec());
124 let live_backup = live_backup.map(|s| s.to_vec());
125 let exhausted = self.services.steward_list.is_exhausted(epoch);
126 let has_list = self.services.steward_list.current_list().is_some();
127 let roles = members
128 .iter()
129 .cloned()
130 .map(|id| {
131 let role = if has_list && !exhausted {
132 if live_epoch.as_deref().is_some_and(|es| es == id) {
133 MemberRole::EpochSteward
134 } else if live_backup.as_deref().is_some_and(|bs| bs == id) {
135 MemberRole::BackupSteward
136 } else if self.services.steward_list.is_steward(&id) {
137 MemberRole::Steward
138 } else {
139 MemberRole::Member
140 }
141 } else if has_list && self.services.steward_list.is_steward(&id) {
142 MemberRole::Steward
143 } else {
144 MemberRole::Member
145 };
146 (id, role)
147 })
148 .collect();
149 Ok(roles)
150 }
151
152 pub fn approved_proposals_for_current_epoch(&self) -> Vec<ConversationUpdateRequest> {
153 self.queues.approved_proposals().values().cloned().collect()
154 }
155}