use anyhow::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PortFormat {
Port,
Addr,
Json,
}
pub fn parse_port_from_addr(addr: &str) -> Option<u16> {
let colon = addr.rfind(':')?;
addr[colon + 1..].parse::<u16>().ok()
}
pub fn format_output(addr: &str, format: PortFormat) -> Option<String> {
match format {
PortFormat::Port => {
let port = parse_port_from_addr(addr)?;
Some(port.to_string())
}
PortFormat::Addr => Some(addr.to_string()),
PortFormat::Json => {
let port = parse_port_from_addr(addr)?;
let colon = addr.rfind(':')?;
let host = &addr[..colon];
Some(format!(r#"{{"addr":"{host}","port":{port}}}"#))
}
}
}
pub fn handle_port(format: PortFormat) -> Result<()> {
let addr = match trusty_common::read_daemon_addr("trusty-search") {
Ok(Some(a)) if !a.is_empty() => a,
Ok(Some(_)) | Ok(None) => {
match read_legacy_port_file() {
Some(port) => format!("127.0.0.1:{port}"),
None => {
eprintln!(
"trusty-search: no daemon running (address file not found). \
Start with `trusty-search start`."
);
std::process::exit(1);
}
}
}
Err(e) => {
eprintln!("trusty-search: could not read daemon address: {e:#}");
std::process::exit(1);
}
};
match format_output(&addr, format) {
Some(out) => {
println!("{out}");
Ok(())
}
None => {
eprintln!(
"trusty-search: daemon address file contains an unrecognised \
address `{addr}` (expected host:port). \
Re-start the daemon with `trusty-search start`."
);
std::process::exit(1);
}
}
}
fn read_legacy_port_file() -> Option<u16> {
let path = crate::commands::daemon_utils::daemon_port_path()?;
let raw = std::fs::read_to_string(path).ok()?;
raw.trim().parse::<u16>().ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn format_port_output_default() {
assert_eq!(
format_output("127.0.0.1:7879", PortFormat::Port),
Some("7879".to_string())
);
}
#[test]
fn format_port_output_addr() {
assert_eq!(
format_output("127.0.0.1:7879", PortFormat::Addr),
Some("127.0.0.1:7879".to_string())
);
}
#[test]
fn format_port_output_json() {
assert_eq!(
format_output("127.0.0.1:7879", PortFormat::Json),
Some(r#"{"addr":"127.0.0.1","port":7879}"#.to_string())
);
}
#[test]
fn format_port_output_ipv6_port() {
assert_eq!(parse_port_from_addr("[::1]:7879"), Some(7879));
}
#[test]
fn format_port_output_malformed_returns_none() {
assert_eq!(format_output("not-an-addr", PortFormat::Port), None);
assert_eq!(format_output("", PortFormat::Port), None);
}
#[test]
fn format_port_output_json_malformed_returns_none() {
assert_eq!(format_output("127.0.0.1:notaport", PortFormat::Json), None);
}
#[test]
fn parse_port_standard() {
assert_eq!(parse_port_from_addr("127.0.0.1:7878"), Some(7878));
}
#[test]
fn parse_port_zero() {
assert_eq!(parse_port_from_addr("127.0.0.1:0"), Some(0));
}
#[test]
fn parse_port_no_colon() {
assert_eq!(parse_port_from_addr("127.0.0.1"), None);
}
#[test]
fn parse_port_overflow() {
assert_eq!(parse_port_from_addr("127.0.0.1:99999"), None);
}
}