elara_diffusion/
authority.rs1use elara_core::NodeId;
7use std::collections::HashSet;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum AuthorityLevel {
12 Exclusive,
14 Shared,
16 Open,
18 Frozen,
20}
21
22#[derive(Debug, Clone)]
24pub struct AuthorityProof {
25 pub claimer: NodeId,
27 pub state_id: u64,
29 pub signature: Vec<u8>,
31 pub timestamp: i64,
33}
34
35impl AuthorityProof {
36 pub fn new(claimer: NodeId, state_id: u64, timestamp: i64) -> Self {
38 Self {
39 claimer,
40 state_id,
41 signature: Vec::new(), timestamp,
43 }
44 }
45
46 pub fn is_for_state(&self, state_id: u64) -> bool {
48 self.state_id == state_id
49 }
50}
51
52#[derive(Debug, Clone)]
54pub struct AuthoritySet {
55 pub state_id: u64,
57
58 pub level: AuthorityLevel,
60
61 pub authorities: HashSet<NodeId>,
63
64 pub delegations: Vec<(NodeId, NodeId)>,
66}
67
68impl AuthoritySet {
69 pub fn exclusive(state_id: u64, owner: NodeId) -> Self {
71 let mut authorities = HashSet::new();
72 authorities.insert(owner);
73
74 Self {
75 state_id,
76 level: AuthorityLevel::Exclusive,
77 authorities,
78 delegations: Vec::new(),
79 }
80 }
81
82 pub fn shared(state_id: u64, owners: Vec<NodeId>) -> Self {
84 Self {
85 state_id,
86 level: AuthorityLevel::Shared,
87 authorities: owners.into_iter().collect(),
88 delegations: Vec::new(),
89 }
90 }
91
92 pub fn open(state_id: u64) -> Self {
94 Self {
95 state_id,
96 level: AuthorityLevel::Open,
97 authorities: HashSet::new(),
98 delegations: Vec::new(),
99 }
100 }
101
102 pub fn frozen(state_id: u64) -> Self {
104 Self {
105 state_id,
106 level: AuthorityLevel::Frozen,
107 authorities: HashSet::new(),
108 delegations: Vec::new(),
109 }
110 }
111
112 pub fn has_authority(&self, node: NodeId) -> bool {
114 match self.level {
115 AuthorityLevel::Exclusive | AuthorityLevel::Shared => self.authorities.contains(&node),
116 AuthorityLevel::Open => true,
117 AuthorityLevel::Frozen => false,
118 }
119 }
120
121 pub fn grant(&mut self, granter: NodeId, grantee: NodeId) -> bool {
123 if self.level != AuthorityLevel::Shared {
124 return false;
125 }
126
127 if !self.authorities.contains(&granter) {
128 return false;
129 }
130
131 self.authorities.insert(grantee);
132 self.delegations.push((granter, grantee));
133 true
134 }
135
136 pub fn revoke(&mut self, revoker: NodeId, revokee: NodeId) -> bool {
138 if self.level != AuthorityLevel::Shared {
139 return false;
140 }
141
142 if !self.authorities.contains(&revoker) {
143 return false;
144 }
145
146 if self.authorities.len() == 1 && self.authorities.contains(&revokee) {
148 return false;
149 }
150
151 self.authorities.remove(&revokee);
152 true
153 }
154}
155
156#[derive(Debug, Clone)]
158pub struct LivestreamAuthority {
159 pub broadcaster: NodeId,
161
162 pub visual_authority: AuthoritySet,
164
165 pub audio_authority: AuthoritySet,
167
168 pub chat_authority: AuthoritySet,
170
171 pub moderators: HashSet<NodeId>,
173}
174
175impl LivestreamAuthority {
176 pub fn new(broadcaster: NodeId, stream_id: u64) -> Self {
178 Self {
179 broadcaster,
180 visual_authority: AuthoritySet::exclusive(stream_id, broadcaster),
181 audio_authority: AuthoritySet::exclusive(stream_id + 1, broadcaster),
182 chat_authority: AuthoritySet::open(stream_id + 2),
183 moderators: HashSet::new(),
184 }
185 }
186
187 pub fn add_moderator(&mut self, moderator: NodeId) {
189 self.moderators.insert(moderator);
190 }
191
192 pub fn can_mutate_visual(&self, node: NodeId) -> bool {
194 self.visual_authority.has_authority(node)
195 }
196
197 pub fn can_mutate_audio(&self, node: NodeId) -> bool {
199 self.audio_authority.has_authority(node)
200 }
201
202 pub fn can_chat(&self, node: NodeId) -> bool {
204 self.chat_authority.has_authority(node)
205 }
206
207 pub fn is_moderator(&self, node: NodeId) -> bool {
209 self.moderators.contains(&node) || node == self.broadcaster
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216
217 #[test]
218 fn test_exclusive_authority() {
219 let owner = NodeId::new(1);
220 let other = NodeId::new(2);
221 let auth = AuthoritySet::exclusive(100, owner);
222
223 assert!(auth.has_authority(owner));
224 assert!(!auth.has_authority(other));
225 }
226
227 #[test]
228 fn test_shared_authority() {
229 let node1 = NodeId::new(1);
230 let node2 = NodeId::new(2);
231 let node3 = NodeId::new(3);
232
233 let mut auth = AuthoritySet::shared(100, vec![node1, node2]);
234
235 assert!(auth.has_authority(node1));
236 assert!(auth.has_authority(node2));
237 assert!(!auth.has_authority(node3));
238
239 assert!(auth.grant(node1, node3));
241 assert!(auth.has_authority(node3));
242 }
243
244 #[test]
245 fn test_open_authority() {
246 let auth = AuthoritySet::open(100);
247
248 assert!(auth.has_authority(NodeId::new(1)));
249 assert!(auth.has_authority(NodeId::new(999)));
250 }
251
252 #[test]
253 fn test_frozen_authority() {
254 let auth = AuthoritySet::frozen(100);
255
256 assert!(!auth.has_authority(NodeId::new(1)));
257 assert!(!auth.has_authority(NodeId::new(999)));
258 }
259
260 #[test]
261 fn test_livestream_authority() {
262 let broadcaster = NodeId::new(1);
263 let viewer = NodeId::new(2);
264
265 let auth = LivestreamAuthority::new(broadcaster, 1000);
266
267 assert!(auth.can_mutate_visual(broadcaster));
268 assert!(!auth.can_mutate_visual(viewer));
269
270 assert!(auth.can_mutate_audio(broadcaster));
271 assert!(!auth.can_mutate_audio(viewer));
272
273 assert!(auth.can_chat(broadcaster));
275 assert!(auth.can_chat(viewer));
276 }
277}