mpc_manager/state/
group.rs

1//! Group state
2//!
3//! This module contains all the logic related to group management.
4
5use super::{
6    parameters::Parameters,
7    session::{Session, SessionId},
8    ClientId,
9};
10use serde::{Deserialize, Serialize};
11use std::collections::{HashMap, HashSet};
12use thiserror::Error;
13use uuid::Uuid;
14
15#[cfg(feature = "server")]
16use super::session::{SessionKind, SessionValue};
17
18/// Unique ID of a group.
19pub type GroupId = Uuid;
20
21/// Error type for group operations.
22#[derive(Debug, Error)]
23pub enum GroupError {
24    /// Error generated when the group is full.
25    #[error("group is full")]
26    GroupFull,
27}
28
29/// Group is a collection of clients. It is the main unit of communication.
30#[derive(Debug, Deserialize, Serialize)]
31pub struct Group {
32    /// Unique ID of the group.
33    pub id: GroupId,
34    /// Parameters of the group.
35    pub params: Parameters,
36    /// Sessions belonging to this group.
37    #[serde(skip)]
38    pub(crate) sessions: HashMap<SessionId, Session>,
39    /// Clients that joined this group.
40    #[serde(skip)]
41    pub(crate) clients: HashSet<ClientId>,
42}
43
44impl Group {
45    /// Creates a new group with the given parameters.
46    pub fn new(id: GroupId, params: Parameters) -> Self {
47        Self {
48            id,
49            params,
50            sessions: HashMap::new(),
51            clients: HashSet::new(),
52        }
53    }
54
55    /// Adds a client to the group.
56    #[cfg(feature = "server")]
57    pub fn add_client(&mut self, client_id: ClientId) -> anyhow::Result<()> {
58        let clients = self.clients.len();
59        if clients >= self.params.n().into() {
60            return Err(GroupError::GroupFull.into());
61        }
62        self.clients.insert(client_id);
63        Ok(())
64    }
65
66    /// Removes a client from the group.
67    #[cfg(feature = "server")]
68    pub fn drop_client(&mut self, client_id: ClientId) {
69        self.clients.remove(&client_id);
70        // FIXME: delete from sessions too
71    }
72
73    /// Adds a new session and adds it to the group.
74    #[cfg(feature = "server")]
75    pub fn add_session(&mut self, kind: SessionKind, value: SessionValue) -> Session {
76        let session_id = Uuid::new_v4();
77        let session = Session::new(session_id, kind, value);
78        let session_c = session.clone();
79        self.sessions.insert(session_id, session);
80        session_c
81    }
82
83    /// Returns a session by its ID, if it exists.
84    #[cfg(feature = "server")]
85    pub fn get_session(&self, session_id: &SessionId) -> Option<&Session> {
86        self.sessions.get(session_id)
87    }
88
89    /// Returns a mutable session by its ID, if it exists.
90    #[cfg(feature = "server")]
91    pub fn get_session_mut(&mut self, session_id: &SessionId) -> Option<&mut Session> {
92        self.sessions.get_mut(session_id)
93    }
94
95    /// Returns a boolean indicating if the group is empty.
96    #[cfg(feature = "server")]
97    pub fn is_empty(&self) -> bool {
98        self.clients.len() == 0
99    }
100
101    /// Returns a boolean indicating if the group is full.
102    #[cfg(feature = "server")]
103    pub fn is_full(&self) -> bool {
104        self.clients.len() == self.params.n() as usize
105    }
106
107    /// Returns the ID of the group.
108    #[cfg(feature = "server")]
109    pub fn id(&self) -> GroupId {
110        self.id
111    }
112
113    /// Returns the client ids associated with the group.
114    #[cfg(feature = "server")]
115    pub fn clients(&self) -> &HashSet<ClientId> {
116        &self.clients
117    }
118}
119
120impl Clone for Group {
121    /// Clones group parameters, disregarding sensitive information.
122    ///
123    /// Should be used only for logging purposes.
124    fn clone(&self) -> Self {
125        Self {
126            id: self.id,
127            params: self.params.clone(),
128            sessions: HashMap::new(),
129            clients: HashSet::new(),
130        }
131    }
132}