mpc_manager/service/
group_service.rs

1//! # Group service
2//!
3//! This module contains the group service that handles incoming requests
4//! for group management.
5
6use crate::state::{
7    group::{Group, GroupId},
8    parameters::Parameters,
9};
10use serde::{Deserialize, Serialize};
11use strum::{Display, EnumString};
12
13#[cfg(feature = "server")]
14use super::{notification::Notification, Service, ServiceResponse};
15#[cfg(feature = "server")]
16use crate::state::{ClientId, State};
17#[cfg(feature = "server")]
18use json_rpc2::{Error, Request};
19#[cfg(feature = "server")]
20use std::str::FromStr;
21#[cfg(feature = "server")]
22use tokio::sync::Mutex;
23
24/// Prefix for group routes.
25pub const ROUTE_PREFIX: &str = "group";
26
27/// Available group methods.
28#[derive(Debug, Display, EnumString)]
29pub enum GroupMethod {
30    #[strum(serialize = "group_create")]
31    GroupCreate,
32    #[strum(serialize = "group_join")]
33    GroupJoin,
34}
35
36/// Group create request.
37#[derive(Deserialize, Serialize)]
38pub struct GroupCreateRequest {
39    pub parameters: Parameters,
40}
41
42/// Group create response.
43#[derive(Deserialize, Serialize)]
44pub struct GroupCreateResponse {
45    pub group: Group,
46}
47
48/// Group join request.
49#[derive(Deserialize, Serialize)]
50pub struct GroupJoinRequest {
51    #[serde(rename = "groupId")]
52    pub group_id: GroupId,
53}
54
55/// Group join response.
56#[derive(Deserialize, Serialize)]
57pub struct GroupJoinResponse {
58    pub group: Group,
59}
60
61/// Group service that handles incoming requests and maps
62/// them to the corresponding methods.
63#[cfg(feature = "server")]
64pub struct GroupService;
65
66#[axum::async_trait]
67#[cfg(feature = "server")]
68impl Service for GroupService {
69    async fn handle(
70        &self,
71        req: &Request,
72        ctx: (
73            std::sync::Arc<State>,
74            std::sync::Arc<Mutex<Vec<Notification>>>,
75        ),
76        client_id: ClientId,
77    ) -> ServiceResponse {
78        let method =
79            GroupMethod::from_str(req.method()).map_err(|_| json_rpc2::Error::MethodNotFound {
80                name: req.method().to_string(),
81                id: req.id().clone(),
82            })?;
83        let response = match method {
84            GroupMethod::GroupCreate => self.group_create(req, ctx, client_id).await?,
85            GroupMethod::GroupJoin => self.group_join(req, ctx, client_id).await?,
86        };
87        Ok(response)
88    }
89}
90
91#[cfg(feature = "server")]
92impl GroupService {
93    async fn group_create(
94        &self,
95        req: &Request,
96        ctx: (
97            std::sync::Arc<State>,
98            std::sync::Arc<Mutex<Vec<Notification>>>,
99        ),
100        client_id: ClientId,
101    ) -> ServiceResponse {
102        tracing::info!("Creating a new group");
103        let params: GroupCreateRequest = req.deserialize()?;
104        let (state, _) = ctx;
105        params
106            .parameters
107            .validate()
108            .map_err(|e| Error::InvalidParams {
109                id: req.id().clone(),
110                data: e.to_string(),
111            })?;
112
113        let group = state.add_group(params.parameters).await;
114        state
115            .join_group(group.id, client_id)
116            .await
117            .map_err(|e| Error::from(Box::from(e)))?;
118        tracing::info!(group_id = group.id().to_string(), "Group created");
119        let res = serde_json::to_value(GroupCreateResponse { group })
120            .map_err(|e| Error::from(Box::from(e)))?;
121        Ok(Some((req, res).into()))
122    }
123
124    async fn group_join(
125        &self,
126        req: &Request,
127        ctx: (
128            std::sync::Arc<State>,
129            std::sync::Arc<Mutex<Vec<Notification>>>,
130        ),
131        client_id: ClientId,
132    ) -> ServiceResponse {
133        let params: GroupJoinRequest = req.deserialize()?;
134        tracing::info!(
135            group_id = params.group_id.to_string(),
136            "Joining client to group"
137        );
138        let (state, _) = ctx;
139        let group = state
140            .join_group(params.group_id, client_id)
141            .await
142            .map_err(|e| Error::InvalidParams {
143                id: req.id().clone(),
144                data: e.to_string(),
145            })?;
146        let res = serde_json::to_value(GroupJoinResponse { group })
147            .map_err(|e| Error::from(Box::from(e)))?;
148        Ok(Some((req, res).into()))
149    }
150}