use std::net::{SocketAddr, SocketAddrV4};
|
|
|
|
use anyhow::bail;
|
|
use solstice_proto::server::PeerAddressResponse;
|
|
|
|
use crate::context::Context;
|
|
use crate::message_handler::MessageHandler;
|
|
use crate::peer::PeerState;
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct PeerAddressResponseHandler;
|
|
|
|
impl MessageHandler for PeerAddressResponseHandler {
|
|
type Message = PeerAddressResponse;
|
|
|
|
fn run(
|
|
self,
|
|
context: &mut Context,
|
|
response: &PeerAddressResponse,
|
|
) -> anyhow::Result<()> {
|
|
match context.state.peers.peers.get_mut(&response.user_name) {
|
|
Some(state @ &mut PeerState::FetchingAddress) => {
|
|
*state = PeerState::Opening {
|
|
address: SocketAddr::V4(SocketAddrV4::new(
|
|
response.ip,
|
|
response.port,
|
|
)),
|
|
};
|
|
}
|
|
entry => bail!("unexpected peer state entry: {:?}", entry),
|
|
};
|
|
|
|
// TODO: try opening a connection to the peer. Queue an event that will be
|
|
// handled later if that fails.
|
|
//
|
|
// Question: should dispatcher_tx be added to Context? Otherwise, how would
|
|
// the asynchronous open task notify the context it is done? If we add it,
|
|
// then how does the dispatcher notice it should stop running?
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn name() -> String {
|
|
"PeerAddressResponseHandler".to_string()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
|
|
|
use solstice_proto::server::PeerAddressResponse;
|
|
|
|
use crate::context::{ContextBundle, ContextOptions};
|
|
use crate::message_handler::MessageHandler;
|
|
use crate::peer::PeerState;
|
|
|
|
use super::PeerAddressResponseHandler;
|
|
|
|
#[test]
|
|
fn run_missing_state() {
|
|
let mut options = ContextOptions::default();
|
|
options.initial_state.peers.peers.insert(
|
|
"aisha".to_string(),
|
|
PeerState::Opening {
|
|
address: "1.2.3.4:42".parse().unwrap(),
|
|
},
|
|
);
|
|
|
|
let mut bundle = ContextBundle::new(options);
|
|
|
|
let response = PeerAddressResponse {
|
|
user_name: "aisha".to_string(),
|
|
ip: Ipv4Addr::new(1, 2, 3, 4),
|
|
port: 42,
|
|
};
|
|
|
|
PeerAddressResponseHandler::default()
|
|
.run(&mut bundle.context, &response)
|
|
.unwrap_err();
|
|
}
|
|
|
|
#[test]
|
|
fn run_wrong_state() {
|
|
let mut bundle = ContextBundle::default();
|
|
|
|
let response = PeerAddressResponse {
|
|
user_name: "aisha".to_string(),
|
|
ip: Ipv4Addr::new(1, 2, 3, 4),
|
|
port: 42,
|
|
};
|
|
|
|
PeerAddressResponseHandler::default()
|
|
.run(&mut bundle.context, &response)
|
|
.unwrap_err();
|
|
}
|
|
|
|
#[test]
|
|
fn run_success() {
|
|
let mut options = ContextOptions::default();
|
|
options
|
|
.initial_state
|
|
.peers
|
|
.peers
|
|
.insert("aisha".to_string(), PeerState::FetchingAddress);
|
|
|
|
let mut bundle = ContextBundle::new(options);
|
|
|
|
let response = PeerAddressResponse {
|
|
user_name: "aisha".to_string(),
|
|
ip: Ipv4Addr::new(1, 2, 3, 4),
|
|
port: 42,
|
|
};
|
|
|
|
PeerAddressResponseHandler::default()
|
|
.run(&mut bundle.context, &response)
|
|
.unwrap();
|
|
|
|
match bundle.context.state.peers.peers.get("aisha") {
|
|
Some(PeerState::Opening { address }) => assert_eq!(
|
|
address,
|
|
&SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 42))
|
|
),
|
|
entry => panic!("unexpected peer state entry: {:?}", entry),
|
|
};
|
|
}
|
|
}
|