use chrono::{Duration, SecondsFormat, Utc}; use uuid::Uuid; pub struct CursorOverTime { pub uuid: Option, pub r#type: Option, pub point_lat: f64, pub point_lon: f64, pub point_hae: f32, pub point_ce: Option, pub point_le: Option, pub contact_callsign: String, pub group_name: Option, pub group_role: Option, pub track_course: Option, pub track_speed: Option, pub link_uid: Option, pub remarker: Option, pub video_url: Option, } impl CursorOverTime { fn escape_xml_attribute(value: &str) -> String { value .replace('&', "&") .replace('"', """) .replace('<', "<") .replace('>', ">") } pub fn convert_to_xml(&self) -> String { let uuid = match &self.uuid { Some(uuid) => uuid, None => &Uuid::new_v4().to_string(), }; let marker_type = match &self.r#type { Some(marker_type) => marker_type, None => &"a-f-G-U-C-I".to_string(), }; let created_time = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); let stale_time = (Utc::now() + Duration::seconds(360)).to_rfc3339_opts(SecondsFormat::Millis, true); let mut xml = String::new(); xml.push_str(""); xml.push_str( format!("", marker_type, uuid, created_time, created_time, stale_time).as_str()); let point_ce = match &self.point_ce { Some(point_ce) => point_ce, None => &9999999.0, }; let point_le = match &self.point_le { Some(point_le) => point_le, None => &9999999.0, }; xml.push_str( format!( "", point_ce, point_le, self.point_hae, self.point_lat, self.point_lon ) .as_str(), ); xml.push_str(""); xml.push_str(""); if let Some(linked_uid) = &self.link_uid { xml.push_str(""); xml.push_str( format!( "", linked_uid, ) .as_str(), ); xml.push_str(""); } xml.push_str(format!("", self.contact_callsign).as_str()); xml.push_str(format!("", self.contact_callsign).as_str()); if let (Some(track_course), Some(track_speed)) = (&self.track_course, &self.track_speed) { xml.push_str( format!( "", track_course, track_speed ) .as_str(), ); xml.push_str(""); } if let (Some(group_name), Some(group_role)) = (&self.group_name, &self.group_role) { xml.push_str( format!( "<__group name=\"{}\" role=\"{}\" />", group_name, group_role ) .as_str(), ); } if let Some(remark) = &self.remarker { xml.push_str(format!("ARMATAK | {}", remark).as_str()); } if let Some(video_url) = &self.video_url { if !video_url.trim().is_empty() { xml.push_str( format!( "<__video url=\"{}\" />", Self::escape_xml_attribute(video_url.trim()) ) .as_str(), ); } } xml.push_str(""); return xml; } }