|
|
|
@ -4,7 +4,7 @@ use bevy::prelude::*; |
|
|
|
use lightyear::prelude::client::*; |
|
|
|
use lightyear::prelude::client::*; |
|
|
|
use lightyear::prelude::*; |
|
|
|
use lightyear::prelude::*; |
|
|
|
|
|
|
|
|
|
|
|
use thiserror::Error; |
|
|
|
use crate::network::DEFAULT_PORT; |
|
|
|
|
|
|
|
|
|
|
|
pub struct ConnectWebTransportCommand { |
|
|
|
pub struct ConnectWebTransportCommand { |
|
|
|
server_addr: SocketAddr, |
|
|
|
server_addr: SocketAddr, |
|
|
|
@ -13,9 +13,8 @@ pub struct ConnectWebTransportCommand { |
|
|
|
|
|
|
|
|
|
|
|
impl ConnectWebTransportCommand { |
|
|
|
impl ConnectWebTransportCommand { |
|
|
|
pub fn new(server_addr: &str, certificate_digest: String) -> Result<Self> { |
|
|
|
pub fn new(server_addr: &str, certificate_digest: String) -> Result<Self> { |
|
|
|
let server_addr = to_socket_addr_with_default_port(server_addr, super::DEFAULT_PORT)?; |
|
|
|
|
|
|
|
Ok(Self { |
|
|
|
Ok(Self { |
|
|
|
server_addr, |
|
|
|
server_addr: resolve_addr(&server_addr, DEFAULT_PORT)?, |
|
|
|
certificate_digest, |
|
|
|
certificate_digest, |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
@ -41,23 +40,31 @@ impl Command for ConnectWebTransportCommand { |
|
|
|
|
|
|
|
|
|
|
|
// TODO: Move this to its own `utils` module?
|
|
|
|
// TODO: Move this to its own `utils` module?
|
|
|
|
// FIXME: Hostname resolving does not work on web.
|
|
|
|
// FIXME: Hostname resolving does not work on web.
|
|
|
|
fn to_socket_addr_with_default_port(addr: &str, default_port: u16) -> Result<SocketAddr> { |
|
|
|
fn resolve_addr(addr: &str, default_port: u16) -> Result<SocketAddr> { |
|
|
|
let has_port = match (addr.rfind(']'), addr.rfind(':')) { |
|
|
|
let addr = with_default_port(addr, default_port); |
|
|
|
|
|
|
|
let socket_addrs = addr.to_socket_addrs()?.collect::<Vec<_>>(); |
|
|
|
|
|
|
|
if let Some(ipv4) = socket_addrs.iter().find(|a| a.is_ipv4()) { |
|
|
|
|
|
|
|
Ok(*ipv4) // Prefer first IPv4 address found..
|
|
|
|
|
|
|
|
} else if let Some(ipv6) = socket_addrs.first() { |
|
|
|
|
|
|
|
Ok(*ipv6) // ..otherwise fallback to IPv6.
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
Err(std::io::Error::other("hostname could not be resolved").into()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn with_default_port(addr: &str, default_port: u16) -> String { |
|
|
|
|
|
|
|
if is_port_specified(addr) { |
|
|
|
|
|
|
|
addr.to_string() |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
format!("{addr}:{default_port}") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn is_port_specified(addr: &str) -> bool { |
|
|
|
|
|
|
|
match (addr.rfind(']'), addr.rfind(':')) { |
|
|
|
// This doesn't match colons within IPv6 brackets, like `[::1]`.
|
|
|
|
// This doesn't match colons within IPv6 brackets, like `[::1]`.
|
|
|
|
(Some(bracket), Some(colon)) if bracket < colon => true, |
|
|
|
(Some(bracket), Some(colon)) if bracket < colon => true, |
|
|
|
(None, Some(_)) => true, |
|
|
|
(None, Some(_)) => true, |
|
|
|
_ => false, |
|
|
|
_ => false, |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut socket_addrs = if has_port { |
|
|
|
|
|
|
|
addr.to_socket_addrs() |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
(addr, default_port).to_socket_addrs() |
|
|
|
|
|
|
|
}?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
socket_addrs.next().ok_or(ResolveError.into()) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
#[derive(Error, Debug)] |
|
|
|
|
|
|
|
#[error("hostname could not be resolved to any address")] |
|
|
|
|
|
|
|
pub struct ResolveError; |
|
|
|
|
|
|
|
|