|
|
|
@ -7,11 +7,7 @@ use solstice_proto::ServerRequest; |
|
|
|
|
|
|
|
use crate::context::Context;
|
|
|
|
use crate::control;
|
|
|
|
use crate::handlers::{
|
|
|
|
RoomListResponseHandler, RoomMessageRequestHandler,
|
|
|
|
RoomMessageResponseHandler,
|
|
|
|
};
|
|
|
|
use crate::message_handler::MessageHandler;
|
|
|
|
use crate::room::RoomMessage;
|
|
|
|
|
|
|
|
/// An event affecting the chat room module.
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
|
|
@ -72,9 +68,7 @@ fn handle_join_request( |
|
|
|
.blocking_send(ServerRequest::RoomJoinRequest(server::RoomJoinRequest {
|
|
|
|
room_name,
|
|
|
|
}))
|
|
|
|
.context("sending server request")?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
.context("sending server request")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn handle_join_response(
|
|
|
|
@ -94,8 +88,7 @@ fn handle_join_response( |
|
|
|
context
|
|
|
|
.control_response_tx
|
|
|
|
.blocking_send(control_response)
|
|
|
|
.context("sending control response")?;
|
|
|
|
Ok(())
|
|
|
|
.context("sending control response")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn handle_list_request(context: &mut Context) -> anyhow::Result<()> {
|
|
|
|
@ -111,8 +104,68 @@ fn handle_list_request(context: &mut Context) -> anyhow::Result<()> { |
|
|
|
context
|
|
|
|
.server_request_tx
|
|
|
|
.blocking_send(ServerRequest::RoomListRequest)
|
|
|
|
.context("sending server request")?;
|
|
|
|
Ok(())
|
|
|
|
.context("sending server request")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn handle_list_response(
|
|
|
|
context: &mut Context,
|
|
|
|
response: server::RoomListResponse,
|
|
|
|
) -> anyhow::Result<()> {
|
|
|
|
context.state.rooms.set_room_list(response);
|
|
|
|
|
|
|
|
let rooms = context.state.rooms.get_room_list();
|
|
|
|
let control_response =
|
|
|
|
control::Response::RoomListResponse(control::RoomListResponse { rooms });
|
|
|
|
|
|
|
|
context
|
|
|
|
.control_response_tx
|
|
|
|
.blocking_send(control_response)
|
|
|
|
.context("sending control response")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn handle_message_request(
|
|
|
|
context: &mut Context,
|
|
|
|
message: control::RoomMessageRequest,
|
|
|
|
) -> anyhow::Result<()> {
|
|
|
|
// TODO: Add message to room.
|
|
|
|
context
|
|
|
|
.server_request_tx
|
|
|
|
.blocking_send(ServerRequest::RoomMessageRequest(
|
|
|
|
server::RoomMessageRequest {
|
|
|
|
room_name: message.room_name,
|
|
|
|
message: message.message,
|
|
|
|
},
|
|
|
|
))
|
|
|
|
.context("sending server request")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn handle_message_response(
|
|
|
|
context: &mut Context,
|
|
|
|
response: server::RoomMessageResponse,
|
|
|
|
) -> anyhow::Result<()> {
|
|
|
|
let room = context
|
|
|
|
.state
|
|
|
|
.rooms
|
|
|
|
.get_mut_strict(&response.room_name)
|
|
|
|
.context("looking up room")?;
|
|
|
|
|
|
|
|
let message = RoomMessage {
|
|
|
|
received_at: context.system_clock.now(),
|
|
|
|
user_name: response.user_name,
|
|
|
|
message: response.message,
|
|
|
|
};
|
|
|
|
|
|
|
|
room.insert_message(message.clone());
|
|
|
|
|
|
|
|
context
|
|
|
|
.control_response_tx
|
|
|
|
.blocking_send(control::Response::RoomMessageResponse(
|
|
|
|
control::RoomMessageResponse {
|
|
|
|
room_name: response.room_name,
|
|
|
|
message,
|
|
|
|
},
|
|
|
|
))
|
|
|
|
.context("sending control response")
|
|
|
|
}
|
|
|
|
|
|
|
|
impl HandleRoomEvent for RoomEventHandler {
|
|
|
|
@ -131,13 +184,13 @@ impl HandleRoomEvent for RoomEventHandler { |
|
|
|
}
|
|
|
|
RoomEvent::ListRequest => handle_list_request(context),
|
|
|
|
RoomEvent::ListResponse(response) => {
|
|
|
|
RoomListResponseHandler::default().run(context, &response)
|
|
|
|
handle_list_response(context, response)
|
|
|
|
}
|
|
|
|
RoomEvent::MessageRequest(request) => {
|
|
|
|
RoomMessageRequestHandler::default().run(context, &request)
|
|
|
|
handle_message_request(context, request)
|
|
|
|
}
|
|
|
|
RoomEvent::MessageResponse(response) => {
|
|
|
|
RoomMessageResponseHandler::default().run(context, &response)
|
|
|
|
handle_message_response(context, response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -168,8 +221,12 @@ pub mod testing { |
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
use std::time::{Duration, SystemTime};
|
|
|
|
|
|
|
|
use solstice_proto::server;
|
|
|
|
|
|
|
|
use crate::clock::SimulatedSystemClock;
|
|
|
|
use crate::context::{ContextBundle, ContextOptions};
|
|
|
|
use crate::room::{RoomMembership, RoomState, RoomVisibility};
|
|
|
|
|
|
|
|
@ -327,6 +384,16 @@ mod tests { |
|
|
|
assert_eq!(request, ServerRequest::RoomListRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
// `sort_by_key()` cannot handle an extractor function that returns
|
|
|
|
// references, so we use `sort_by()` and a comparator instead.
|
|
|
|
// See: https://github.com/rust-lang/rust/issues/34162
|
|
|
|
fn compare_by_name(
|
|
|
|
lhs: &(String, RoomState),
|
|
|
|
rhs: &(String, RoomState),
|
|
|
|
) -> Ordering {
|
|
|
|
lhs.0.cmp(&rhs.0)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn handle_list_request_sends_immediate_response() {
|
|
|
|
let mut options = ContextOptions::default();
|
|
|
|
@ -355,12 +422,40 @@ mod tests { |
|
|
|
_ => panic!("Unexpected control response: {:?}", response),
|
|
|
|
};
|
|
|
|
|
|
|
|
// `sort_by_key()` cannot handle an extractor function that returns
|
|
|
|
// references, so we use `sort_by()` instead.
|
|
|
|
// See: https://github.com/rust-lang/rust/issues/34162
|
|
|
|
rooms.sort_unstable_by(|(ref lhs_name, _), (ref rhs_name, _)| {
|
|
|
|
lhs_name.cmp(rhs_name)
|
|
|
|
});
|
|
|
|
rooms.sort_unstable_by(compare_by_name);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
rooms,
|
|
|
|
vec![
|
|
|
|
(
|
|
|
|
"apple".to_string(),
|
|
|
|
RoomState::new(RoomVisibility::Public, 42)
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"potato".to_string(),
|
|
|
|
RoomState::new(RoomVisibility::Public, 123)
|
|
|
|
),
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn handle_list_response_sets_room_list() {
|
|
|
|
let mut bundle = ContextBundle::default();
|
|
|
|
|
|
|
|
let response = server::RoomListResponse {
|
|
|
|
rooms: vec![("potato".to_string(), 123), ("apple".to_string(), 42)],
|
|
|
|
owned_private_rooms: vec![],
|
|
|
|
other_private_rooms: vec![],
|
|
|
|
operated_private_room_names: vec![],
|
|
|
|
};
|
|
|
|
|
|
|
|
RoomEventHandler
|
|
|
|
.handle(&mut bundle.context, RoomEvent::ListResponse(response))
|
|
|
|
.expect("handling response");
|
|
|
|
|
|
|
|
let mut rooms = bundle.context.state.rooms.get_room_list();
|
|
|
|
rooms.sort_unstable_by(compare_by_name);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
rooms,
|
|
|
|
@ -376,4 +471,131 @@ mod tests { |
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn handle_message_request_forwards_request() {
|
|
|
|
let mut bundle = ContextBundle::default();
|
|
|
|
|
|
|
|
RoomEventHandler
|
|
|
|
.handle(
|
|
|
|
&mut bundle.context,
|
|
|
|
RoomEvent::MessageRequest(control::RoomMessageRequest {
|
|
|
|
room_name: "bleep".to_string(),
|
|
|
|
message: "yo!".to_string(),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.expect("handling request");
|
|
|
|
|
|
|
|
let request = bundle
|
|
|
|
.server_request_rx
|
|
|
|
.blocking_recv()
|
|
|
|
.expect("receiving request");
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
request,
|
|
|
|
ServerRequest::RoomMessageRequest(server::RoomMessageRequest {
|
|
|
|
room_name: "bleep".to_string(),
|
|
|
|
message: "yo!".to_string(),
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn system_time_from_secs(seconds: u64) -> SystemTime {
|
|
|
|
SystemTime::UNIX_EPOCH + Duration::from_secs(seconds)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn handle_message_response_forwards_response() {
|
|
|
|
let mut options = ContextOptions::default();
|
|
|
|
options.initial_state.rooms.insert(
|
|
|
|
"apple".to_string(),
|
|
|
|
RoomState::new(RoomVisibility::Public, 1),
|
|
|
|
);
|
|
|
|
options.simulated_clock =
|
|
|
|
Some(SimulatedSystemClock::new(system_time_from_secs(42)));
|
|
|
|
|
|
|
|
let mut bundle = ContextBundle::new(options);
|
|
|
|
|
|
|
|
RoomEventHandler
|
|
|
|
.handle(
|
|
|
|
&mut bundle.context,
|
|
|
|
RoomEvent::MessageResponse(server::RoomMessageResponse {
|
|
|
|
room_name: "apple".to_string(),
|
|
|
|
user_name: "shruti".to_string(),
|
|
|
|
message: "yo!".to_string(),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.expect("handling response");
|
|
|
|
|
|
|
|
let response = bundle
|
|
|
|
.control_response_rx
|
|
|
|
.blocking_recv()
|
|
|
|
.expect("receiving control response");
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
response,
|
|
|
|
control::Response::RoomMessageResponse(control::RoomMessageResponse {
|
|
|
|
room_name: "apple".to_string(),
|
|
|
|
message: RoomMessage {
|
|
|
|
user_name: "shruti".to_string(),
|
|
|
|
message: "yo!".to_string(),
|
|
|
|
received_at: SystemTime::UNIX_EPOCH + Duration::from_secs(42),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn handle_message_response_stores_message() {
|
|
|
|
let mut room = RoomState::new(RoomVisibility::Public, 42);
|
|
|
|
room.messages.insert(RoomMessage {
|
|
|
|
received_at: system_time_from_secs(42),
|
|
|
|
user_name: "karandeep".to_string(),
|
|
|
|
message: "namaste!".to_string(),
|
|
|
|
});
|
|
|
|
|
|
|
|
let mut options = ContextOptions::default();
|
|
|
|
options
|
|
|
|
.initial_state
|
|
|
|
.rooms
|
|
|
|
.insert("apple".to_string(), room.clone());
|
|
|
|
options.simulated_clock =
|
|
|
|
Some(SimulatedSystemClock::new(system_time_from_secs(43)));
|
|
|
|
|
|
|
|
let mut bundle = ContextBundle::new(options);
|
|
|
|
|
|
|
|
RoomEventHandler
|
|
|
|
.handle(
|
|
|
|
&mut bundle.context,
|
|
|
|
RoomEvent::MessageResponse(server::RoomMessageResponse {
|
|
|
|
room_name: "apple".to_string(),
|
|
|
|
user_name: "shruti".to_string(),
|
|
|
|
message: "yo!".to_string(),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.expect("handling response");
|
|
|
|
|
|
|
|
let room = bundle
|
|
|
|
.context
|
|
|
|
.state
|
|
|
|
.rooms
|
|
|
|
.get_strict("apple")
|
|
|
|
.expect("looking up room");
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
room.clone_state().messages.to_vec(),
|
|
|
|
vec![
|
|
|
|
RoomMessage {
|
|
|
|
received_at: system_time_from_secs(42),
|
|
|
|
user_name: "karandeep".to_string(),
|
|
|
|
message: "namaste!".to_string(),
|
|
|
|
},
|
|
|
|
RoomMessage {
|
|
|
|
received_at: system_time_from_secs(43),
|
|
|
|
user_name: "shruti".to_string(),
|
|
|
|
message: "yo!".to_string(),
|
|
|
|
},
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|