diff --git a/src/cot_generator.rs b/src/cot_generator.rs new file mode 100644 index 0000000..cb72b42 --- /dev/null +++ b/src/cot_generator.rs @@ -0,0 +1,210 @@ +use arma_rs::{FromArma, FromArmaError}; +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, +} + +impl CursorOverTime { + 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(""); + + 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(), + ); + } + + xml.push_str(""); + + return xml; + } +} + +pub struct HumanCoTPayload { + pub uuid: String, + pub point_lat: f64, + pub point_lon: f64, + pub point_hae: f32, + pub contact_callsign: String, + pub group_name: String, + pub group_role: String, + pub track_course: i32, + pub track_speed: f32, +} + +impl FromArma for HumanCoTPayload { + fn from_arma(data: String) -> Result { + let ( + uuid, + point_lat, + point_lon, + point_hae, + contact_callsign, + group_name, + group_role, + track_course, + track_speed, + ) = <(String, f64, f64, f32, String, String, String, i32, f32)>::from_arma(data)?; + Ok(Self { + uuid, + point_lat, + point_lon, + point_hae, + contact_callsign, + group_name, + group_role, + track_course, + track_speed, + }) + } +} + +impl HumanCoTPayload { + pub fn to_cot(&self) -> CursorOverTime { + CursorOverTime { + uuid: Some(self.uuid.clone()), + r#type: None, + point_lat: self.point_lat, + point_lon: self.point_lon, + point_hae: self.point_hae, + point_ce: None, + point_le: None, + contact_callsign: self.contact_callsign.clone(), + group_name: Some(self.group_name.clone()), + group_role: Some(self.group_role.clone()), + track_course: Some(self.track_course), + track_speed: Some(self.track_speed), + } + } +} + +pub struct MarkerCoTPayload { + pub uuid: String, + pub r#type: String, + pub point_lat: f64, + pub point_lon: f64, + pub point_hae: f32, + pub contact_callsign: String, + pub track_course: i32, + pub track_speed: f32, +} + +impl FromArma for MarkerCoTPayload { + fn from_arma(data: String) -> Result { + let ( + uuid, + r#type, + point_lat, + point_lon, + point_hae, + contact_callsign, + track_course, + track_speed, + ) = <(String, String, f64, f64, f32, String, i32, f32)>::from_arma(data)?; + Ok(Self { + uuid, + r#type, + point_lat, + point_lon, + point_hae, + contact_callsign, + track_course, + track_speed, + }) + } +} + +impl MarkerCoTPayload { + pub fn to_cot(&self) -> CursorOverTime { + CursorOverTime { + uuid: Some(self.uuid.clone()), + r#type: Some(self.r#type.clone()), + point_lat: self.point_lat, + point_lon: self.point_lon, + point_hae: self.point_hae, + point_ce: None, + point_le: None, + contact_callsign: self.contact_callsign.clone(), + group_name: None, + group_role: None, + track_course: Some(self.track_course), + track_speed: Some(self.track_speed), + } + } +} diff --git a/src/cot_router.rs b/src/cot_router.rs index 40ba1df..1bbc715 100644 --- a/src/cot_router.rs +++ b/src/cot_router.rs @@ -6,6 +6,8 @@ use std::sync::{Arc, Mutex}; use std::thread; use lazy_static::lazy_static; +use crate::cot_generator::{HumanCoTPayload, MarkerCoTPayload}; + pub enum TcpCommand { SendMessage(String), Stop, @@ -27,7 +29,6 @@ impl TcpClient { thread::spawn(move || { let mut running = true; - // TCP connection thread let tcp_thread = thread::spawn(move || { match TcpStream::connect(&address) { Ok(stream) => { @@ -66,11 +67,17 @@ impl TcpClient { } pub fn send_payload(&self, payload: String) { - self.tx.send(TcpCommand::SendMessage(payload)).unwrap(); + let tx = self.tx.clone(); + thread::spawn(move || { + tx.send(TcpCommand::SendMessage(payload)).unwrap(); + }); } pub fn stop(&self) { - self.tx.send(TcpCommand::Stop).unwrap(); + let tx = self.tx.clone(); + thread::spawn(move || { + tx.send(TcpCommand::Stop).unwrap(); + }); } } @@ -103,6 +110,16 @@ pub fn send_payload(payload: String) -> &'static str { "Sending payload to TCP server" } +pub fn send_human_cot(cursor_over_time: HumanCoTPayload) -> &'static str { + let payload = cursor_over_time.to_cot().convert_to_xml(); + send_payload(payload) +} + +pub fn send_marker_cot(cursor_over_time: MarkerCoTPayload) -> &'static str { + let payload = cursor_over_time.to_cot().convert_to_xml(); + send_payload(payload) +} + pub fn stop() -> &'static str { if let Some(ref client) = *TCP_CLIENT.lock().unwrap() { client.stop(); @@ -112,4 +129,4 @@ pub fn stop() -> &'static str { } "Stopping TCP Client" -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 1c5b0a6..d4f29ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,9 @@ pub fn init() -> Extension { "cot_router", Group::new() .command("start", cot_router::start) - .command("send_cot", cot_router::send_payload) + .command("send_payload", cot_router::send_payload) + .command("send_human_cot", cot_router::send_human_cot) + .command("send_marker_cot", cot_router::send_marker_cot) .command("stop", cot_router::stop) ) .finish()