From 7a0f9620b2f6802538eb9bf138d4859bed98ed54 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Wed, 10 Feb 2021 18:04:03 +0100 Subject: [PATCH] Can leave a call --- src/api_data/left_call_message.rs | 25 ++++++++++++ src/api_data/mod.rs | 3 +- src/controllers/calls_controller.rs | 57 ++++++++++++++++++++++++++- src/controllers/user_ws_controller.rs | 16 ++++++-- src/controllers/user_ws_routes.rs | 1 + src/data/user.rs | 6 +++ src/data/user_ws_request_handler.rs | 5 +++ src/helpers/events_helper.rs | 11 +++++- 8 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 src/api_data/left_call_message.rs diff --git a/src/api_data/left_call_message.rs b/src/api_data/left_call_message.rs new file mode 100644 index 0000000..9d0ea16 --- /dev/null +++ b/src/api_data/left_call_message.rs @@ -0,0 +1,25 @@ +//! # Left 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 left a call +#[derive(Serialize)] +#[allow(non_snake_case)] +pub struct LeftCallMessage { + callID: u64, + userID: u64, +} + +impl LeftCallMessage { + 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 cab165c..00cf520 100644 --- a/src/api_data/mod.rs +++ b/src/api_data/mod.rs @@ -59,4 +59,5 @@ pub mod res_create_custom_emoji; pub mod res_get_ws_token; pub mod user_calls_config; pub mod joined_call_message; -pub mod call_member_info; \ No newline at end of file +pub mod call_member_info; +pub mod left_call_message; \ No newline at end of file diff --git a/src/controllers/calls_controller.rs b/src/controllers/calls_controller.rs index 9221871..4f168d6 100644 --- a/src/controllers/calls_controller.rs +++ b/src/controllers/calls_controller.rs @@ -6,14 +6,16 @@ use std::collections::HashMap; use crate::api_data::call_member_info::CallMemberInfo; use crate::api_data::joined_call_message::JoinedCallMessage; +use crate::api_data::left_call_message::LeftCallMessage; 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::conversation::ConvID; 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_connection::{ActiveCall, UserWsConnection}; use crate::data::user_ws_message::UserWsMessage; use crate::data::user_ws_request_handler::UserWsRequestHandler; use crate::helpers::{calls_helper, conversations_helper, events_helper}; @@ -57,11 +59,29 @@ pub fn join_call(r: &mut UserWsRequestHandler) -> RequestResult { }))?; // Propagate event - events_helper::propagate_event(&Event::UserJoinedCall(conv_id, r.user_id()?))?; + events_helper::propagate_event(&Event::UserJoinedCall(&conv_id, r.user_id_ref()?))?; Ok(()) } +/// Leave a call +pub fn leave_call(r: &mut UserWsRequestHandler) -> RequestResult { + // Warning ! For some technical reasons, we do not check if the user + // really belongs to the conversation, so be careful when manipulating + // conversation ID here + let conv_id = r.post_u64("convID")?; + + // Check if the user was not in the conversation + if !r.get_conn().is_having_call_with_conversation(&conv_id) { + return r.success("Left call!"); + } + + // Make the user leave the call + make_user_leave_call(&conv_id, r.get_conn())?; + + r.success("Left call!") +} + /// Get the list of members of a call pub fn get_members_list(r: &mut UserWsRequestHandler) -> RequestResult { let conv_id = r.post_call_id("callID")?; @@ -79,6 +99,25 @@ pub fn get_members_list(r: &mut UserWsRequestHandler) -> RequestResult { } +/// Make the user leave the call +pub fn make_user_leave_call(conv_id: &ConvID, connection: &UserWsConnection) -> Res { + connection.clone().replace(|c| c.active_call = None); + + // Notify user (if possible) + if connection.session.connected() { + user_ws_controller::send_to_client(connection, &UserWsMessage::no_id_message("call_closed", conv_id)?)?; + } + + // TODO : call main stream (sender) + + // TODO : close receiver streams (other users streams) + + // Create a notification + events_helper::propagate_event(&Event::UserLeftCall(conv_id, &connection.user_id))?; + + Ok(()) +} + /// Events handler pub fn handle_event(e: &events_helper::Event) -> Res { match e { @@ -90,6 +129,20 @@ pub fn handle_event(e: &events_helper::Event) -> Res { )?; } + Event::UserLeftCall(conv_id, user_id) => { + user_ws_controller::send_message_to_specific_connections( + |c| c.is_having_call_with_conversation(conv_id), + |_| UserWsMessage::no_id_message("user_left_call", LeftCallMessage::new(conv_id, user_id)), + None:: _>, + )?; + } + + Event::UserWsClosed(c) => { + if let Some(call) = c.active_call.clone() { + make_user_leave_call(&call.conv_id, c)?; + } + } + _ => {} } diff --git a/src/controllers/user_ws_controller.rs b/src/controllers/user_ws_controller.rs index eeab586..ed3b06a 100644 --- a/src/controllers/user_ws_controller.rs +++ b/src/controllers/user_ws_controller.rs @@ -119,8 +119,8 @@ mod ws_connections_list { continue; } - do_update(&mut self); - list[i] = self.clone(); + do_update(&mut list[i]); + self = list[i].clone(); break; } @@ -324,7 +324,12 @@ impl Actor for WsSession { } fn stopping(&mut self, ctx: &mut Self::Context) -> Running { - // TODO : send an event (user_ws_closed) + // Send an event (user_ws_closed) + if let Some(conn) = find_connection(ctx.address()) { + if let Err(e) = events_helper::propagate_event(&Event::UserWsClosed(&conn)) { + eprintln!("Failed to propagate web socket closed event ! {:#?}", e); + } + } remove_connection(ctx.address()); Running::Stop @@ -490,6 +495,11 @@ pub fn send_message_to_user(msg: &UserWsMessage, user: &UserID) -> Res { Ok(()) } +/// Send a message to a specific connection +pub fn send_to_client(conn: &UserWsConnection, msg: &UserWsMessage) -> Res { + send_message(conn.session.clone(), msg) +} + /// 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(&UserWsConnection) -> bool, diff --git a/src/controllers/user_ws_routes.rs b/src/controllers/user_ws_routes.rs index 82eff11..0eef054 100644 --- a/src/controllers/user_ws_routes.rs +++ b/src/controllers/user_ws_routes.rs @@ -40,6 +40,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), + UserWsRoute::new("calls/leave", calls_controller::leave_call), UserWsRoute::new("calls/members", calls_controller::get_members_list), ] } diff --git a/src/data/user.rs b/src/data/user.rs index 5cbce0a..19f4ce5 100644 --- a/src/data/user.rs +++ b/src/data/user.rs @@ -44,6 +44,12 @@ impl Hash for UserID { } } +impl PartialEq<&UserID> for UserID { + fn eq(&self, other: &&UserID) -> bool { + self.0 == other.0 + } +} + #[derive(Debug, PartialEq)] pub enum UserPageStatus { OPEN, diff --git a/src/data/user_ws_request_handler.rs b/src/data/user_ws_request_handler.rs index cf74ad9..78f0d7a 100644 --- a/src/data/user_ws_request_handler.rs +++ b/src/data/user_ws_request_handler.rs @@ -51,6 +51,11 @@ impl UserWsRequestHandler { return self.response.unwrap(); } + /// Get a pointer to the websocket connection + pub fn get_conn(&self) -> &UserWsConnection { + &self.connection + } + /// Update information about the WebSocket connection pub fn update_conn(&mut self, do_updates: H) -> ResultBoxError where H: FnOnce(&mut UserWsConnection) { self.connection = self.connection.clone().replace(do_updates); diff --git a/src/helpers/events_helper.rs b/src/helpers/events_helper.rs index 001d231..2acbd1a 100644 --- a/src/helpers/events_helper.rs +++ b/src/helpers/events_helper.rs @@ -11,8 +11,14 @@ use crate::data::conversation::ConvID; use crate::data::conversation_message::ConversationMessage; use crate::data::error::Res; use crate::data::user::UserID; +use crate::data::user_ws_connection::UserWsConnection; pub enum Event<'a> { + /// Websocket of a user was closed + /// + /// This event is propagated BEFORE the removal of the connection from the list + UserWsClosed(&'a UserWsConnection), + /// Destroyed a login token DestroyedLoginToken(UserID, &'a APIClient), @@ -44,7 +50,10 @@ pub enum Event<'a> { ClosedRTCRelayWebSocket, /// User joined call - UserJoinedCall(ConvID, UserID), + UserJoinedCall(&'a ConvID, &'a UserID), + + /// User left call + UserLeftCall(&'a ConvID, &'a UserID), /// No event None,