///|
/// Formats an IPv4 address returned by the socket package in network byte
/// order.
fn format_ipv4_address(ip : UInt) -> String {
"\{ip >> 24}.\{(ip >> 16) & 255}.\{(ip >> 8) & 255}.\{ip & 255}"
}
///|
/// Resolves the IPv4 address selected by the operating system's default
/// route. Connecting a UDP socket selects an interface without transmitting a
/// packet; failure simply omits the optional Network URL at startup.
async fn default_route_ipv4_address() -> String? {
let probe = Some(@socket.UdpClient(@socket.Addr::parse("192.0.2.1:80"))) catch {
_ => None
}
guard probe is Some(probe) else { return None }
let address = probe.addr
probe.close()
if address.is_ipv6() || address.ip() == 0 || address.ip() == 0x7f000001 {
None
} else {
Some(format_ipv4_address(address.ip()))
}
}
///|
fn editor_server_url(host : String, port : Int) -> String {
"http://\{host}:\{port}/"
}
///|
/// Builds the reachable startup URLs for the selected bind address. A
/// wildcard listener accepts both loopback and LAN traffic; a concrete address
/// is reported only through the route on which it was bound.
fn editor_server_listening_messages(
bind_host : String,
port : Int,
network_host : String?,
) -> Array[String] {
let messages = ["Readonly editor native server listening on:"]
if bind_host == "0.0.0.0" {
messages.push(" Local: \{editor_server_url("127.0.0.1", port)}")
match network_host {
Some(host) => messages.push(" Network: \{editor_server_url(host, port)}")
None =>
messages.push(
" Network: use this device's LAN IPv4 address on port \{port}",
)
}
messages.push(
" WARNING: no authentication; use only on a trusted network.",
)
} else if bind_host == "127.0.0.1" {
messages.push(" Local: \{editor_server_url(bind_host, port)}")
} else {
messages.push(" Network: \{editor_server_url(bind_host, port)}")
messages.push(
" WARNING: no authentication; use only on a trusted network.",
)
}
messages
}