use std::convert::TryFrom; use chrono::{DateTime, Utc}; use xml::attribute::OwnedAttribute; use crate::dsn::error::ParseError; fn get_attr(attrs: &[OwnedAttribute], name: &str) -> Result { attrs .iter() .find_map(|o| { if o.name.local_name.eq(name) { Some(o.value.clone()) } else { None } }) .ok_or(ParseError::AttrMissing) } #[derive(Clone, Debug)] pub struct Station { pub name: String, pub friendly_name: String, pub time_utc: u64, pub tz_offset: i64, pub dishes: Vec, } impl Station { pub fn add_dish(mut self, dish: Dish) -> Self { self.dishes.push(dish); self } } impl TryFrom> for Station { type Error = ParseError; fn try_from(attrs: Vec) -> Result { let name = get_attr(&attrs, "name")?; let friendly_name = get_attr(&attrs, "friendlyName")?; let time_utc = get_attr(&attrs, "timeUTC")?.parse::()?; let tz_offset = get_attr(&attrs, "timeZoneOffset")?.parse::()?; Ok(Self { name, friendly_name, time_utc, tz_offset, dishes: Vec::new(), }) } } #[derive(Clone, Debug, Eq, PartialEq)] pub enum SignalType { Data, Carrier, None, Unkown(String), } impl From for SignalType { fn from(s: String) -> Self { match s.to_lowercase().as_str() { "data" => SignalType::Data, "carrier" => SignalType::Carrier, "none" => SignalType::None, _ => SignalType::Unkown(s), } } } impl Default for SignalType { fn default() -> Self { SignalType::None } } #[derive(Clone, Debug, Default)] pub struct Signal { pub signal_type: SignalType, pub signal_type_debug: String, pub data_rate: Option, pub frequency: Option, pub power: Option, pub spacecraft: String, pub spacecraft_id: Option, } impl TryFrom> for Signal { type Error = ParseError; fn try_from(attrs: Vec) -> Result { let signal_type = SignalType::from(get_attr(&attrs, "signalType")?); let signal_type_debug = get_attr(&attrs, "signalTypeDebug")?; let data_rate = get_attr(&attrs, "dataRate")?.parse::().ok(); let frequency = get_attr(&attrs, "frequency")?.parse::().ok(); let power = get_attr(&attrs, "power")?.parse::().ok(); let spacecraft = get_attr(&attrs, "spacecraft")?; let spacecraft_id = get_attr(&attrs, "spacecraftId")?.parse::().ok(); Ok(Self { signal_type, signal_type_debug, data_rate, frequency, power, spacecraft, spacecraft_id, }) } } #[derive(Clone, Debug, Default)] pub struct Target { pub name: String, pub id: u32, /// Up Leg Range (km) pub upleg_range: f64, /// Down Leg Leg Range (km) pub downleg_range: f64, /// Round trip light time (s) pub rtlt: f64, } impl TryFrom> for Target { type Error = ParseError; fn try_from(attrs: Vec) -> Result { let name = get_attr(&attrs, "name")?; let id = get_attr(&attrs, "id")?.parse::()?; let upleg_range = get_attr(&attrs, "uplegRange")?.parse::()?; let downleg_range = get_attr(&attrs, "downlegRange")?.parse::()?; let rtlt = get_attr(&attrs, "rtlt")?.parse::()?; Ok(Self { name, id, upleg_range, downleg_range, rtlt, }) } } #[derive(Clone, Debug)] pub struct Dish { pub name: String, pub azimuth_angle: Option, pub elevation_angle: Option, pub wind_speed: Option, pub is_mspa: bool, pub is_array: bool, pub is_ddor: bool, pub created: DateTime, pub updated: DateTime, pub up_signal: Vec, pub down_signal: Vec, pub target: Vec, } impl Dish { pub fn add_up_signal(mut self, signal: Signal) -> Self { self.up_signal.push(signal); self } pub fn add_down_signal(mut self, signal: Signal) -> Self { self.down_signal.push(signal); self } pub fn add_target(mut self, target: Target) -> Self { self.target.push(target); self } } impl TryFrom> for Dish { type Error = ParseError; fn try_from(attrs: Vec) -> Result { let name = get_attr(&attrs, "name")?; let azimuth_angle = get_attr(&attrs, "azimuthAngle")?.parse::().ok(); let elevation_angle = get_attr(&attrs, "elevationAngle")?.parse::().ok(); let wind_speed = get_attr(&attrs, "windSpeed")?.parse::().ok(); let is_mspa = get_attr(&attrs, "isMSPA")?.parse::()?; let is_array = get_attr(&attrs, "isArray")?.parse::()?; let is_ddor = get_attr(&attrs, "isDDOR")?.parse::()?; let created = get_attr(&attrs, "created")?.parse::>()?; let updated = get_attr(&attrs, "updated")?.parse::>()?; Ok(Self { name, azimuth_angle, elevation_angle, wind_speed, is_mspa, is_array, is_ddor, created, updated, up_signal: Vec::new(), down_signal: Vec::new(), target: Vec::new(), }) } }