diff --git a/src/api_data/joined_call_message.rs b/src/api_data/joined_call_message.rs new file mode 100644 index 0000000..ab114c8 --- /dev/null +++ b/src/api_data/joined_call_message.rs @@ -0,0 +1,25 @@ +//! # Joined call message +//! +//! @author Pierre Hubert + +use serde::Serialize; + +use crate::data::conversation::ConvID; +use crate::data::user::UserID; + +/// This structure is used to give information about a user who joined a call +#[derive(Serialize)] +#[allow(non_snake_case)] +pub struct JoinedCallMessage { + callID: u64, + userID: u64, +} + +impl JoinedCallMessage { + pub fn new(call_id: &ConvID, user_id: &UserID) -> Self { + Self { + callID: call_id.clone(), + userID: user_id.id(), + } + } +} \ No newline at end of file diff --git a/src/api_data/mod.rs b/src/api_data/mod.rs index 2343c55..f1375e7 100644 --- a/src/api_data/mod.rs +++ b/src/api_data/mod.rs @@ -57,4 +57,5 @@ pub mod security_settings_api; pub mod account_image_settings_api; pub mod res_create_custom_emoji; pub mod res_get_ws_token; -pub mod user_calls_config; \ No newline at end of file +pub mod user_calls_config; +pub mod joined_call_message; \ No newline at end of file diff --git a/src/controllers/calls_controller.rs b/src/controllers/calls_controller.rs index 62eb468..974d429 100644 --- a/src/controllers/calls_controller.rs +++ b/src/controllers/calls_controller.rs @@ -4,13 +4,19 @@ use std::collections::HashMap; +use crate::api_data::joined_call_message::JoinedCallMessage; use crate::api_data::user_calls_config::UserCallsConfig; use crate::controllers::routes::RequestResult; +use crate::controllers::user_ws_controller; use crate::data::base_request_handler::BaseRequestHandler; use crate::data::config::conf; -use crate::data::error::ExecError; +use crate::data::error::{ExecError, Res}; use crate::data::http_request_handler::HttpRequestHandler; +use crate::data::user_ws_connection::ActiveCall; +use crate::data::user_ws_message::UserWsMessage; use crate::data::user_ws_request_handler::UserWsRequestHandler; +use crate::helpers::{calls_helper, conversations_helper, events_helper}; +use crate::helpers::events_helper::Event; /// Get legacy call configuration pub fn get_legacy_config(r: &mut HttpRequestHandler) -> RequestResult { @@ -29,4 +35,45 @@ pub fn get_config(r: &mut UserWsRequestHandler) -> RequestResult { } r.internal_error(ExecError::boxed_new("Missing calls configuration!")) +} + +/// Join a call +pub fn join_call(r: &mut UserWsRequestHandler) -> RequestResult { + let conv_id = r.post_conv_id("convID")?; + + // Check if the conversation can have a call + let conv = conversations_helper::get_single(conv_id, r.user_id_ref()?)?; + if !calls_helper::can_have_call(&conv) { + r.forbidden("This conversation can not be used to make calls!".to_string())?; + } + + // TODO : Remove any previous call linked to current connection + any other active connection + // of current user to current conversation call + + r.update_conn(|r| r.active_call = Some(ActiveCall { + conv_id, + ready: false, + }))?; + + // Propagate event + events_helper::propagate_event(&Event::UserJoinedCall(conv_id, r.user_id()?))?; + + Ok(()) +} + +/// Events handler +pub fn handle_event(e: &events_helper::Event) -> Res { + match e { + Event::UserJoinedCall(conv_id, user_id) => { + user_ws_controller::send_message_to_specific_connections( + |c| c.is_having_call_with_conversation(conv_id) && &c.user_id != user_id, + |_| UserWsMessage::no_id_message("user_joined_call", JoinedCallMessage::new(conv_id, user_id)), + None:: _>, + )?; + } + + _ => {} + } + + Ok(()) } \ No newline at end of file diff --git a/src/controllers/conversations_controller.rs b/src/controllers/conversations_controller.rs index 49a98ec..bc3d05b 100644 --- a/src/controllers/conversations_controller.rs +++ b/src/controllers/conversations_controller.rs @@ -13,13 +13,13 @@ use crate::api_data::res_create_conversation::ResCreateConversation; use crate::api_data::res_find_private_conversations::ResFindPrivateConversations; use crate::controllers::routes::RequestResult; use crate::controllers::user_ws_controller; -use crate::controllers::user_ws_controller::WsConnection; use crate::data::base_request_handler::BaseRequestHandler; use crate::data::error::Res; use crate::data::http_request_handler::HttpRequestHandler; use crate::data::new_conversation::NewConversation; use crate::data::new_conversation_message::NewConversationMessage; use crate::data::user::UserID; +use crate::data::user_ws_connection::UserWsConnection; use crate::data::user_ws_message::UserWsMessage; use crate::helpers::{conversations_helper, events_helper, user_helper}; use crate::helpers::events_helper::Event; @@ -362,7 +362,7 @@ pub fn handle_event(e: &events_helper::Event) -> Res { user_ws_controller::send_message_to_specific_connections( |f| f.conversations.contains(&msg.conv_id), |_| UserWsMessage::no_id_message("new_conv_message", ConversationMessageAPI::new(msg)), - Some(|conn: &WsConnection| conversations_helper::mark_user_seen(msg.conv_id, &conn.user_id)), + Some(|conn: &UserWsConnection| conversations_helper::mark_user_seen(msg.conv_id, &conn.user_id)), )?; } diff --git a/src/controllers/user_ws_controller.rs b/src/controllers/user_ws_controller.rs index b59f270..f7c9443 100644 --- a/src/controllers/user_ws_controller.rs +++ b/src/controllers/user_ws_controller.rs @@ -14,7 +14,6 @@ use serde_json::Value; use crate::api_data::res_get_ws_token::ResGetWsToken; use crate::constants::{USER_LAST_ACTIVITY_REFRESH, WS_ACCESS_TOKEN_LENGTH}; use crate::controllers::user_ws_controller::ws_connections_list::{add_connection, find_connection, get_ws_connections_list, remove_connection}; -pub use crate::controllers::user_ws_controller::ws_connections_list::WsConnection; use crate::controllers::user_ws_routes::find_user_ws_route; use crate::data::api_client::APIClient; use crate::data::base_request_handler::BaseRequestHandler; @@ -22,6 +21,7 @@ use crate::data::config::conf; use crate::data::error::{ExecError, Res, ResultBoxError}; use crate::data::http_request_handler::HttpRequestHandler; use crate::data::user::UserID; +use crate::data::user_ws_connection::UserWsConnection; use crate::data::user_ws_message::UserWsMessage; use crate::data::user_ws_request_handler::{UserWsRequestHandler, UserWsResponseType}; use crate::helpers::{account_helper, events_helper}; @@ -100,30 +100,15 @@ mod ws_tokens_list { /// WebSocket connections list mod ws_connections_list { - use std::collections::HashSet; use std::sync::Arc; use std::sync::Mutex; use actix::Addr; use crate::controllers::user_ws_controller::WsSession; - use crate::data::conversation::ConvID; - use crate::data::post::PostID; - use crate::data::user::UserID; + use crate::data::user_ws_connection::UserWsConnection; - /// This structure contains information about an active connection - #[derive(Clone, Debug)] - pub struct WsConnection { - pub user_id: UserID, - pub client_id: u32, - pub remote_ip: String, - pub session: actix::Addr, - pub incognito: bool, - pub conversations: HashSet, - pub posts: HashSet, - } - - impl WsConnection { + impl UserWsConnection { /// Change some of the properties of the connection pub fn replace(mut self, do_update: H) -> Self where H: FnOnce(&mut Self) { let list = get_ws_connections_list(); @@ -147,23 +132,23 @@ mod ws_connections_list { } lazy_static! { - static ref WS_CONNECTIONS: Arc>> = { + static ref WS_CONNECTIONS: Arc>> = { Arc::new(Mutex::new(Vec::new())) }; } /// Get the list of WebSocket connections - pub fn get_ws_connections_list() -> Arc>> { + pub fn get_ws_connections_list() -> Arc>> { (*WS_CONNECTIONS).clone() } /// Add a new token to the list - pub fn add_connection(t: WsConnection) { + pub fn add_connection(t: UserWsConnection) { get_ws_connections_list().lock().unwrap().push(t) } /// Find a connection in the list - pub fn find_connection(t: Addr) -> Option { + pub fn find_connection(t: Addr) -> Option { get_ws_connections_list() .lock() .unwrap() @@ -173,7 +158,7 @@ mod ws_connections_list { } /// Remove a connection from the list - pub fn remove_connection(t: Addr) -> Option { + pub fn remove_connection(t: Addr) -> Option { let list = get_ws_connections_list(); let mut list = list.lock().unwrap(); for i in 0..list.len() { @@ -326,7 +311,7 @@ impl Actor for WsSession { self.hb(ctx); self.user_activity(ctx); - add_connection(WsConnection { + add_connection(UserWsConnection { user_id: self.user_id.clone(), client_id: self.client_id, remote_ip: self.remote_ip.clone(), @@ -334,6 +319,7 @@ impl Actor for WsSession { incognito: self.incognito, conversations: HashSet::new(), posts: HashSet::new(), + active_call: None, }) } @@ -506,9 +492,9 @@ pub fn send_message_to_user(msg: &UserWsMessage, user: &UserID) -> Res { /// Send a message to specific users pub fn send_message_to_specific_connections(filter: F, msg_generator: M, after_send: Option) -> Res - where F: Fn(&WsConnection) -> bool, - M: Fn(&WsConnection) -> Res, - A: Fn(&WsConnection) -> Res + where F: Fn(&UserWsConnection) -> bool, + M: Fn(&UserWsConnection) -> Res, + A: Fn(&UserWsConnection) -> Res { let connections = get_ws_connections_list() .lock() @@ -516,7 +502,7 @@ pub fn send_message_to_specific_connections(filter: F, msg_generator: M .iter() .filter(|f| filter(f)) .map(|f| f.clone()) - .collect::>(); + .collect::>(); for con in connections { send_message(con.session.clone(), &msg_generator(&con)?)?; diff --git a/src/controllers/user_ws_routes.rs b/src/controllers/user_ws_routes.rs index 1dabc30..f3fe605 100644 --- a/src/controllers/user_ws_routes.rs +++ b/src/controllers/user_ws_routes.rs @@ -39,6 +39,7 @@ pub fn get_user_ws_routes() -> Vec { // Calls controller UserWsRoute::new("calls/config", calls_controller::get_config), + UserWsRoute::new("calls/join", calls_controller::join_call), ] } diff --git a/src/data/mod.rs b/src/data/mod.rs index 1385e28..01d23f7 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -36,4 +36,5 @@ pub mod general_settings; pub mod lang_settings; pub mod security_settings; pub mod new_custom_emoji; -pub mod user_ws_message; \ No newline at end of file +pub mod user_ws_message; +pub mod user_ws_connection; \ No newline at end of file diff --git a/src/data/user_ws_connection.rs b/src/data/user_ws_connection.rs new file mode 100644 index 0000000..7f0c983 --- /dev/null +++ b/src/data/user_ws_connection.rs @@ -0,0 +1,36 @@ +use std::collections::HashSet; + +use crate::controllers::user_ws_controller::WsSession; +use crate::data::conversation::ConvID; +use crate::data::post::PostID; +use crate::data::user::UserID; + +#[derive(Clone, Debug)] +pub struct ActiveCall { + pub conv_id: ConvID, + pub ready: bool, +} + +/// This structure contains information about an active connection +#[derive(Clone, Debug)] +pub struct UserWsConnection { + pub user_id: UserID, + pub client_id: u32, + pub remote_ip: String, + pub session: actix::Addr, + pub incognito: bool, + pub conversations: HashSet, + pub posts: HashSet, + pub active_call: Option, +} + +impl UserWsConnection { + /// Check out whether a connection is being used to make a call in a specific conversation or not + pub fn is_having_call_with_conversation(&self, conv_id: &ConvID) -> bool { + if let Some(call_info) = &self.active_call { + return &call_info.conv_id == conv_id; + } + + false + } +} \ No newline at end of file diff --git a/src/data/user_ws_request_handler.rs b/src/data/user_ws_request_handler.rs index e3ca2e8..de48f5b 100644 --- a/src/data/user_ws_request_handler.rs +++ b/src/data/user_ws_request_handler.rs @@ -6,10 +6,10 @@ use serde::Serialize; use crate::api_data::http_error::HttpError; use crate::controllers::routes::RequestResult; -use crate::controllers::user_ws_controller::WsConnection; use crate::data::base_request_handler::{BaseRequestHandler, RequestValue}; use crate::data::error::ResultBoxError; use crate::data::user::UserID; +use crate::data::user_ws_connection::UserWsConnection; pub enum UserWsResponseType { SUCCESS, @@ -22,13 +22,13 @@ pub struct UserWsResponse { } pub struct UserWsRequestHandler { - connection: WsConnection, + connection: UserWsConnection, args: HashMap, response: Option, } impl UserWsRequestHandler { - pub fn new(connection: &WsConnection, args: HashMap) -> UserWsRequestHandler { + pub fn new(connection: &UserWsConnection, args: HashMap) -> UserWsRequestHandler { UserWsRequestHandler { connection: connection.clone(), args: args.into_iter().map(|f| (f.0, RequestValue::String(f.1))).collect(), @@ -51,7 +51,7 @@ impl UserWsRequestHandler { } /// Update information about the WebSocket connection - pub fn update_conn(&mut self, do_updates: H) -> ResultBoxError where H: FnOnce(&mut WsConnection) { + pub fn update_conn(&mut self, do_updates: H) -> ResultBoxError where H: FnOnce(&mut UserWsConnection) { self.connection = self.connection.clone().replace(do_updates); Ok(()) diff --git a/src/helpers/events_helper.rs b/src/helpers/events_helper.rs index e668706..001d231 100644 --- a/src/helpers/events_helper.rs +++ b/src/helpers/events_helper.rs @@ -4,9 +4,10 @@ -use crate::controllers::{comments_controller, conversations_controller, notifications_controller, user_ws_controller}; +use crate::controllers::{calls_controller, comments_controller, conversations_controller, notifications_controller, user_ws_controller}; use crate::data::api_client::APIClient; use crate::data::comment::Comment; +use crate::data::conversation::ConvID; use crate::data::conversation_message::ConversationMessage; use crate::data::error::Res; use crate::data::user::UserID; @@ -42,6 +43,9 @@ pub enum Event<'a> { /// Connection to RTC relay was closed ClosedRTCRelayWebSocket, + /// User joined call + UserJoinedCall(ConvID, UserID), + /// No event None, } @@ -52,5 +56,6 @@ pub fn propagate_event(e: &Event) -> Res { comments_controller::handle_event(e)?; notifications_controller::handle_event(e)?; user_ws_controller::handle_event(e)?; + calls_controller::handle_event(e)?; Ok(()) } \ No newline at end of file