@ -9,6 +9,7 @@ use crate::context::Context;
use crate ::control ::Request as ControlRequest ;
use crate ::control ::Request as ControlRequest ;
use crate ::handlers ::* ;
use crate ::handlers ::* ;
use crate ::message_handler ::MessageHandler ;
use crate ::message_handler ::MessageHandler ;
use crate ::room_controller ::{ HandleRoomEvent , RoomEvent , RoomEventHandler } ;
/// The type of messages dispatched by a dispatcher.
/// The type of messages dispatched by a dispatcher.
#[ derive(Debug, Eq, PartialEq) ]
#[ derive(Debug, Eq, PartialEq) ]
@ -17,6 +18,7 @@ pub enum Message {
ServerResponse ( ServerResponse ) ,
ServerResponse ( ServerResponse ) ,
}
}
// TODO: Remove?
impl From < ServerResponse > for Message {
impl From < ServerResponse > for Message {
fn from ( response : ServerResponse ) -> Self {
fn from ( response : ServerResponse ) -> Self {
Self ::ServerResponse ( response )
Self ::ServerResponse ( response )
@ -29,229 +31,351 @@ impl From<ControlRequest> for Message {
}
}
}
}
/// Represents a synchronous task that can be run against a context.
pub trait Job : Send {
/// Runs this job against the given context.
fn execute ( self : Box < Self > , context : & mut Context ) ;
pub struct DispatcherHandlersView < 'a > {
room_event_handler : & 'a mut dyn HandleRoomEvent ,
}
}
/// Pairs together a message and its handler as chosen by the dispatcher.
/// Implements Job so as to erase the exact types involved.
struct DispatchedMessage < H , M > {
message : M ,
handler : H ,
#[ derive(Default) ]
pub struct DefaultDispatcherHandlers {
room_event_handler : RoomEventHandler ,
}
}
impl < H > Job for DispatchedMessage < H , < H as MessageHandler > ::Message >
where
H : MessageHandler + Send ,
< H as MessageHandler > ::Message : Debug + Send ,
{
fn execute ( self : Box < Self > , context : & mut Context ) {
if let Err ( error ) = self . handler . run ( context , & self . message ) {
error ! (
"Error in handler {}: {:?}\nMessage: {:?}" ,
H ::name ( ) ,
error ,
& self . message
) ;
impl DefaultDispatcherHandlers {
pub fn view < 'a > ( & 'a mut self ) -> DispatcherHandlersView < 'a > {
DispatcherHandlersView {
room_event_handler : & mut self . room_event_handler ,
}
}
}
}
}
}
pub struct DispatcherParts < 'a > {
pub context : Context ,
pub handlers : DispatcherHandlersView < 'a > ,
}
/// The Dispatcher is in charge of mapping messages to their handlers.
/// The Dispatcher is in charge of mapping messages to their handlers.
pub struct Dispatcher ;
pub struct Dispatcher < 'a > {
pub context : Context ,
pub handlers : DispatcherHandlersView < 'a > ,
}
impl Dispatcher {
impl < 'a > Dispatcher < 'a > {
/// Returns a new dispatcher.
/// Returns a new dispatcher.
pub fn new ( ) -> Self {
Self { }
pub fn from_parts ( parts : DispatcherParts < 'a > ) -> Self {
Self {
context : parts . context ,
handlers : parts . handlers ,
}
}
}
/// Dispatches the given message by wrapping it with a handler.
pub fn dispatch ( & self , message : Message ) -> Option < Box < dyn Job > > {
pub fn into_parts ( self ) -> DispatcherParts < 'a > {
DispatcherParts {
context : self . context ,
handlers : self . handlers ,
}
}
fn dispatch_internal ( & mut self , message : Message ) -> anyhow ::Result < ( ) > {
match message {
match message {
Message ::ControlRequest ( ControlRequest ::LoginStatusRequest ) = > {
Some ( Box ::new ( DispatchedMessage {
message : ( ) ,
handler : LoginStatusRequestHandler ::default ( ) ,
} ) )
}
Message ::ServerResponse ( ServerResponse ::PeerAddressResponse (
Message ::ServerResponse ( ServerResponse ::PeerAddressResponse (
response ,
response ,
) ) = > Some ( Box ::new ( DispatchedMessage {
message : response ,
handler : PeerAddressResponseHandler ::default ( ) ,
} ) ) ,
) ) = > {
PeerAddressResponseHandler ::default ( ) . run ( & mut self . context , & response )
}
Message ::ServerResponse ( ServerResponse ::PrivilegedUsersResponse (
Message ::ServerResponse ( ServerResponse ::PrivilegedUsersResponse (
response ,
response ,
) ) = > Some ( Box ::new ( DispatchedMessage {
message : response ,
handler : PrivilegedUsersResponseHandler ::default ( ) ,
} ) ) ,
) ) = > PrivilegedUsersResponseHandler ::default ( )
. run ( & mut self . context , & response ) ,
Message ::ServerResponse ( ServerResponse ::RoomJoinResponse ( response ) ) = > {
Message ::ServerResponse ( ServerResponse ::RoomJoinResponse ( response ) ) = > {
Some ( Box ::new ( DispatchedMessage {
message : response ,
handler : RoomJoinResponseHandler ::default ( ) ,
} ) )
self
. handlers
. room_event_handler
. handle ( & mut self . context , RoomEvent ::JoinResponse ( response ) )
}
}
Message ::ServerResponse ( ServerResponse ::RoomMessageResponse (
Message ::ServerResponse ( ServerResponse ::RoomMessageResponse (
response ,
response ,
) ) = > Some ( Box ::new ( DispatchedMessage {
message : response ,
handler : RoomMessageResponseHandler ::default ( ) ,
} ) ) ,
) ) = > self
. handlers
. room_event_handler
. handle ( & mut self . context , RoomEvent ::MessageResponse ( response ) ) ,
Message ::ServerResponse ( ServerResponse ::RoomListResponse ( response ) ) = > {
Message ::ServerResponse ( ServerResponse ::RoomListResponse ( response ) ) = > {
Some ( Box ::new ( DispatchedMessage {
message : response ,
handler : RoomListResponseHandler ::default ( ) ,
} ) )
self
. handlers
. room_event_handler
. handle ( & mut self . context , RoomEvent ::ListResponse ( response ) )
}
}
Message ::ServerResponse ( response ) = > {
Message ::ServerResponse ( response ) = > {
warn ! ( "Unhandled server response: {:?}" , response ) ;
warn ! ( "Unhandled server response: {:?}" , response ) ;
None
Ok ( ( ) )
}
}
Message ::ControlRequest ( ControlRequest ::PeerConnectRequest ( request ) ) = > {
Some ( Box ::new ( DispatchedMessage {
message : request ,
handler : PeerConnectRequestHandler ::default ( ) ,
} ) )
Message ::ControlRequest ( ControlRequest ::LoginStatusRequest ) = > {
LoginStatusRequestHandler ::default ( ) . run ( & mut self . context , & ( ) )
}
}
Message ::ControlRequest ( ControlRequest ::RoomListRequest ) = > {
Some ( Box ::new ( DispatchedMessage {
message : ( ) ,
handler : RoomListRequestHandler ::default ( ) ,
} ) )
Message ::ControlRequest ( ControlRequest ::PeerConnectRequest ( request ) ) = > {
PeerConnectRequestHandler ::default ( ) . run ( & mut self . context , & request )
}
}
Message ::ControlRequest ( ControlRequest ::RoomListRequest ) = > self
. handlers
. room_event_handler
. handle ( & mut self . context , RoomEvent ::ListRequest ) ,
Message ::ControlRequest ( ControlRequest ::RoomMessageRequest ( request ) ) = > {
Message ::ControlRequest ( ControlRequest ::RoomMessageRequest ( request ) ) = > {
Some ( Box ::new ( DispatchedMessage {
message : request ,
handler : RoomMessageRequestHandler ::default ( ) ,
} ) )
self
. handlers
. room_event_handler
. handle ( & mut self . context , RoomEvent ::MessageRequest ( request ) )
}
}
Message ::ControlRequest ( ControlRequest ::RoomJoinRequest ( room_name ) ) = > {
Message ::ControlRequest ( ControlRequest ::RoomJoinRequest ( room_name ) ) = > {
Some ( Box ::new ( DispatchedMessage {
message : room_name ,
handler : RoomJoinRequestHandler ::default ( ) ,
} ) )
self
. handlers
. room_event_handler
. handle ( & mut self . context , RoomEvent ::JoinRequest ( room_name ) )
}
}
Message ::ControlRequest ( ControlRequest ::UserListRequest ) = > {
Message ::ControlRequest ( ControlRequest ::UserListRequest ) = > {
Some ( Box ::new ( DispatchedMessage {
message : ( ) ,
handler : UserListRequestHandler ::default ( ) ,
} ) )
UserListRequestHandler ::default ( ) . run ( & mut self . context , & ( ) )
}
}
Message ::ControlRequest ( request ) = > {
Message ::ControlRequest ( request ) = > {
warn ! ( "Unhandled control request: {:?}" , request ) ;
warn ! ( "Unhandled control request: {:?}" , request ) ;
None
Ok ( ( ) )
}
}
}
}
}
}
/// Dispatches the given message by wrapping it with a handler.
pub fn dispatch ( & mut self , message : Message ) {
let debug_message = format ! ( "{:?}" , & message ) ;
if let Err ( error ) = self . dispatch_internal ( message ) {
error ! (
"Error handling message: {:?}\nMessage: {}" ,
error , debug_message
) ;
}
}
}
}
#[ cfg(test) ]
#[ cfg(test) ]
mod tests {
mod tests {
use crate ::control ;
use crate ::dispatcher ::Message ;
use std ::net ::Ipv4Addr ;
use solstice_proto ::server ;
use solstice_proto ::server ;
use crate ::context ::ContextBundle ;
use crate ::control ;
use crate ::dispatcher ::Message ;
use crate ::room_controller ::testing ::FakeRoomEventHandler ;
use super ::* ;
use super ::* ;
#[ derive(Default) ]
struct FakeDispatcherHandlers {
room_event_handler : FakeRoomEventHandler ,
}
impl FakeDispatcherHandlers {
fn view < 'a > ( & 'a mut self ) -> DispatcherHandlersView < 'a > {
DispatcherHandlersView {
room_event_handler : & mut self . room_event_handler ,
}
}
fn has_events ( & self ) -> bool {
! self . room_event_handler . events . is_empty ( )
}
}
/// Dispatches `message` to `handlers` using a new `Dispatcher` and `Context`.
fn dispatch ( message : Message , handlers : & mut FakeDispatcherHandlers ) {
let bundle = ContextBundle ::default ( ) ;
let mut dispatcher = Dispatcher ::from_parts ( DispatcherParts {
context : bundle . context ,
handlers : handlers . view ( ) ,
} ) ;
dispatcher . dispatch ( message ) ;
}
#[ test ]
#[ test ]
fn does_not_dispatch_unhandled_response ( ) {
fn does_not_dispatch_unhandled_response ( ) {
assert ! ( Dispatcher ::new ( )
. dispatch ( Message ::ServerResponse (
server ::LoginResponse ::LoginFail {
reason : "bleep bloop" . to_string ( ) ,
}
. into ( )
) )
. is_none ( ) ) ;
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let response = server ::LoginResponse ::LoginFail {
reason : "bleep bloop" . to_string ( ) ,
} ;
dispatch ( Message ::ServerResponse ( response . into ( ) ) , & mut handlers ) ;
assert ! ( ! handlers . has_events ( ) ) ;
}
#[ test ]
fn dispatches_login_status_request ( ) {
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let request = control ::Request ::LoginStatusRequest ;
dispatch ( request . into ( ) , & mut handlers ) ;
// TODO: Check that event is dispatched to a new login event handler.
}
#[ test ]
fn dispatches_peer_address_response ( ) {
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let response = server ::PeerAddressResponse {
user_name : "shruti" . to_string ( ) ,
ip : Ipv4Addr ::new ( 1 , 2 , 3 , 4 ) ,
port : 1234 ,
} ;
dispatch ( Message ::ServerResponse ( response . into ( ) ) , & mut handlers ) ;
// TODO: Check that event is dispatched to a new peer event handler.
}
#[ test ]
fn dispatches_peer_connect_request ( ) {
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let request = control ::Request ::PeerConnectRequest ( "shruti" . to_string ( ) ) ;
dispatch ( Message ::ControlRequest ( request ) , & mut handlers ) ;
// TODO: Check that event is dispatched to a new peer event handler.
}
}
#[ test ]
#[ test ]
fn dispatches_privileged_users_response ( ) {
fn dispatches_privileged_users_response ( ) {
assert ! ( Dispatcher ::new ( )
. dispatch ( Message ::ServerResponse (
server ::PrivilegedUsersResponse {
users : vec ! [ "foo" . to_string ( ) , "bar" . to_string ( ) , "baz" . to_string ( ) ] ,
}
. into ( )
) )
. is_some ( ) ) ;
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let response = server ::PrivilegedUsersResponse {
users : vec ! [ "foo" . to_string ( ) , "bar" . to_string ( ) , "baz" . to_string ( ) ] ,
} ;
dispatch ( Message ::ServerResponse ( response . into ( ) ) , & mut handlers ) ;
// TODO: Check that event is dispatched to a new user event handler.
}
#[ test ]
fn dispatches_room_join_request ( ) {
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let request = control ::Request ::RoomJoinRequest ( "bleep" . to_string ( ) ) ;
dispatch ( Message ::ControlRequest ( request . into ( ) ) , & mut handlers ) ;
assert_eq ! (
handlers . room_event_handler . events ,
& [ RoomEvent ::JoinRequest ( "bleep" . to_string ( ) ) ] ,
) ;
}
}
#[ test ]
#[ test ]
fn dispatches_room_join_response ( ) {
fn dispatches_room_join_response ( ) {
assert ! ( Dispatcher ::new ( )
. dispatch ( Message ::ServerResponse (
server ::RoomJoinResponse {
room_name : "bleep" . to_string ( ) ,
owner : None ,
operators : Vec ::new ( ) ,
users : Vec ::new ( ) ,
}
. into ( )
) )
. is_some ( ) ) ;
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let response = server ::RoomJoinResponse {
room_name : "bleep" . to_string ( ) ,
owner : None ,
operators : Vec ::new ( ) ,
users : Vec ::new ( ) ,
} ;
dispatch (
Message ::ServerResponse ( response . clone ( ) . into ( ) ) ,
& mut handlers ,
) ;
assert_eq ! (
handlers . room_event_handler . events ,
& [ RoomEvent ::JoinResponse ( response ) ]
) ;
}
}
#[ test ]
#[ test ]
fn dispatches_room_message_response ( ) {
assert ! ( Dispatcher ::new ( )
. dispatch ( Message ::ServerResponse (
server ::RoomMessageResponse {
room_name : "bleep" . to_string ( ) ,
user_name : "shruti" . to_string ( ) ,
message : "yo!" . to_string ( ) ,
}
. into ( )
) )
. is_some ( ) ) ;
fn dispatches_room_list_request ( ) {
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
dispatch ( control ::Request ::RoomListRequest . into ( ) , & mut handlers ) ;
assert_eq ! (
handlers . room_event_handler . events ,
& [ RoomEvent ::ListRequest ]
) ;
}
}
#[ test ]
#[ test ]
fn dispatches_room_list_response ( ) {
fn dispatches_room_list_response ( ) {
assert ! ( Dispatcher ::new ( )
. dispatch ( Message ::ServerResponse (
server ::RoomListResponse {
rooms : Vec ::new ( ) ,
owned_private_rooms : Vec ::new ( ) ,
other_private_rooms : Vec ::new ( ) ,
operated_private_room_names : Vec ::new ( ) ,
}
. into ( )
) )
. is_some ( ) ) ;
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let response = server ::RoomListResponse {
rooms : Vec ::new ( ) ,
owned_private_rooms : Vec ::new ( ) ,
other_private_rooms : Vec ::new ( ) ,
operated_private_room_names : Vec ::new ( ) ,
} ;
dispatch (
Message ::ServerResponse ( response . clone ( ) . into ( ) ) ,
& mut handlers ,
) ;
assert_eq ! (
handlers . room_event_handler . events ,
& [ RoomEvent ::ListResponse ( response ) ]
) ;
}
}
#[ test ]
#[ test ]
fn dispatches_room_join_request ( ) {
assert ! ( Dispatcher ::new ( )
. dispatch ( Message ::ControlRequest (
control ::Request ::RoomJoinRequest ( "bleep" . to_string ( ) ) . into ( )
) )
. is_some ( ) ) ;
fn dispatches_room_message_request ( ) {
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let request = control ::RoomMessageRequest {
room_name : "bleep" . to_string ( ) ,
message : "yo!" . to_string ( ) ,
} ;
dispatch (
Message ::ControlRequest ( request . clone ( ) . into ( ) ) ,
& mut handlers ,
) ;
assert_eq ! (
handlers . room_event_handler . events ,
& [ RoomEvent ::MessageRequest ( request ) ] ,
) ;
}
}
#[ test ]
#[ test ]
fn dispatches_room_message_request ( ) {
assert ! ( Dispatcher ::new ( )
. dispatch ( Message ::ControlRequest (
control ::RoomMessageRequest {
room_name : "bleep" . to_string ( ) ,
message : "yo!" . to_string ( ) ,
}
. into ( )
) )
. is_some ( ) ) ;
fn dispatches_room_message_response ( ) {
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let response = server ::RoomMessageResponse {
room_name : "bleep" . to_string ( ) ,
user_name : "shruti" . to_string ( ) ,
message : "yo!" . to_string ( ) ,
} ;
dispatch (
Message ::ServerResponse ( response . clone ( ) . into ( ) ) ,
& mut handlers ,
) ;
assert_eq ! (
handlers . room_event_handler . events ,
& [ RoomEvent ::MessageResponse ( response ) ]
) ;
}
}
#[ test ]
#[ test ]
fn dispatches_room_list_request ( ) {
assert ! ( Dispatcher ::new ( )
. dispatch ( Message ::ControlRequest ( control ::Request ::RoomListRequest ) )
. is_some ( ) ) ;
fn dispatches_user_list_request ( ) {
let mut handlers = FakeDispatcherHandlers ::default ( ) ;
let request = control ::Request ::UserListRequest ;
dispatch ( request . into ( ) , & mut handlers ) ;
// TODO: Check that event is dispatched to a new user event handler.
}
}
}
}