diff --git a/client/src/room/event.rs b/client/src/room/event.rs index aee5845..374d7c4 100644 --- a/client/src/room/event.rs +++ b/client/src/room/event.rs @@ -1,15 +1,17 @@ //! This module defines events affecting the room module and their handling. +use anyhow::Context as AnyhowContext; +use log::error; use solstice_proto::server::{ - RoomJoinResponse, RoomListResponse, RoomMessageResponse, + RoomJoinRequest, RoomJoinResponse, RoomListResponse, RoomMessageResponse, }; +use solstice_proto::ServerRequest; use crate::context::Context; -use crate::control::RoomMessageRequest; +use crate::control::{self, RoomMessageRequest}; use crate::handlers::{ - RoomJoinRequestHandler, RoomJoinResponseHandler, RoomListRequestHandler, - RoomListResponseHandler, RoomMessageRequestHandler, - RoomMessageResponseHandler, + RoomJoinResponseHandler, RoomListRequestHandler, RoomListResponseHandler, + RoomMessageRequestHandler, RoomMessageResponseHandler, }; use crate::message_handler::MessageHandler; @@ -40,6 +42,43 @@ pub trait HandleRoomEvent { #[derive(Default)] pub struct RoomEventHandler; +fn start_joining(context: &mut Context, room_name: &str) -> anyhow::Result<()> { + let room = context.state.rooms.get_mut_strict(room_name)?; + + room.start_joining().map_err(|err| { + let response = + control::Response::RoomJoinResponse(control::RoomJoinResponse { + room_name: room_name.to_string(), + room: room.clone_state(), + }); + + if let Err(err) = context.control_response_tx.blocking_send(response) { + error!( + "Failed to send RoomJoinResponse for room {}: {}", + room_name, err + ); + } + + err.into() + }) +} + +fn handle_join_request( + context: &mut Context, + room_name: String, +) -> anyhow::Result<()> { + start_joining(context, &room_name).context("joining room")?; + + context + .server_request_tx + .blocking_send(ServerRequest::RoomJoinRequest(RoomJoinRequest { + room_name, + })) + .context("sending server request")?; + + Ok(()) +} + impl HandleRoomEvent for RoomEventHandler { fn handle( &mut self, @@ -49,7 +88,7 @@ impl HandleRoomEvent for RoomEventHandler { // TODO: Remove individual handlers, move code into RoomEventHandler. match event { RoomEvent::JoinRequest(room_name) => { - RoomJoinRequestHandler::default().run(context, &room_name) + handle_join_request(context, room_name) } RoomEvent::JoinResponse(response) => { RoomJoinResponseHandler::default().run(context, &response) @@ -95,5 +134,104 @@ pub mod testing { #[cfg(test)] mod tests { - // TODO + use crate::context::ContextBundle; + + use super::*; + + #[test] + fn run_failure() -> anyhow::Result<()> { + let mut bundle = ContextBundle::default(); + + RoomEventHandler + .handle( + &mut bundle.context, + RoomEvent::JoinRequest("bleep".to_string()), + ) + .unwrap_err(); + + // Room state has not changed. + assert_eq!(bundle.context.state.rooms.get_room_list(), vec![]); + + // Close the channel, so we can observe it was empty without hanging. + drop(bundle.context.server_request_tx); + assert_eq!(bundle.server_request_rx.blocking_recv(), None); + + Ok(()) + } + + /* + #[test] + fn run_already_joined_responds_immediately() -> anyhow::Result<()> { + let mut room = RoomState::new(RoomVisibility::Public, 3); + room.membership = RoomMembership::Member; + + let mut options = ContextOptions::default(); + options + .initial_state + .rooms + .insert("bleep".to_string(), room.clone()); + let mut bundle = ContextBundle::new(options); + + RoomJoinRequestHandler::default() + .run(&mut bundle.context, &"bleep".to_string()) + .unwrap_err(); + + // Room state has not changed. + assert_eq!( + bundle.context.state.rooms.get_room_list(), + vec![("bleep".to_string(), room.clone())] + ); + + assert_eq!( + bundle.control_response_rx.blocking_recv(), + Some(control::Response::RoomJoinResponse( + control::RoomJoinResponse { + room_name: "bleep".to_string(), + room, + } + )) + ); + + Ok(()) + } + + #[test] + fn run_success() -> anyhow::Result<()> { + let mut options = ContextOptions::default(); + options.initial_state.rooms.insert( + "bleep".to_string(), + RoomState::new(RoomVisibility::Public, 3), + ); + let mut bundle = ContextBundle::new(options); + + RoomJoinRequestHandler::default() + .run(&mut bundle.context, &"bleep".to_string()) + .context("running handler")?; + + let request = bundle.server_request_rx.blocking_recv().unwrap(); + + // Room state has been altered to reflect the request. + assert_eq!( + bundle + .context + .state + .rooms + .get_strict("bleep") + .context("getting room")? + .clone_state() + .membership, + RoomMembership::Joining + ); + + // The request is forwarded onwards. + assert_eq!( + request, + ServerRequest::RoomJoinRequest(RoomJoinRequest { + room_name: "bleep".to_string(), + }) + ); + + Ok(()) + } + */ }