use benthic_protocol::messages::ui::login_error::{LoginError, Reason};
use benthic_protocol::messages::ui::login_event::Login;
use metaverse_messages::http::login::login_response::{LoginResponse, LoginStatus};
use metaverse_messages::http::login::simulator_login_protocol::SimulatorLoginProtocol;
pub async fn login_to_simulator(
login: Login,
) -> Result<(LoginResponse, std::net::IpAddr), LoginError> {
let url = login.url.clone();
let local_ip = {
let parsed_url = url::Url::parse(&url).map_err(|e| LoginError {
reason: Reason::Connection,
message: format!("Invalid URL: {:?}", e),
})?;
let host = parsed_url.host_str().ok_or(LoginError {
reason: Reason::Connection,
message: "URL has no host".into(),
})?;
let port = parsed_url.port_or_known_default().ok_or(LoginError {
reason: Reason::Connection,
message: "URL has no port".into(),
})?;
let stream = std::net::TcpStream::connect((host, port)).map_err(|e| LoginError {
reason: Reason::Connection,
message: format!("TCP connect failed: {:?}", e),
})?;
stream
.local_addr()
.map(|addr| addr.ip())
.map_err(|e| LoginError {
reason: Reason::Connection,
message: format!("Failed to get local IP: {:?}", e),
})?
};
let client = awc::Client::default();
let xml = SimulatorLoginProtocol::new(login).to_xmlrpc();
let mut response = client
.post(&url)
.insert_header(("Content-Type", "text/xml; charset=utf-8"))
.send_body(xml)
.await
.map_err(|e| LoginError {
reason: Reason::Connection,
message: format!("{:?}", e),
})?;
let body_bytes = response.body().await.map_err(|e| LoginError {
reason: Reason::Connection,
message: format!("{:?}", e),
})?;
let xml_string = String::from_utf8(body_bytes.to_vec()).unwrap();
match LoginResponse::from_xmlrpc(&xml_string) {
Ok(login) => match login {
LoginStatus::Success(success) => Ok((*success, local_ip)),
LoginStatus::Failure(failure) => Err(failure),
},
Err(e) => Err(e)?,
}
}