diff --git a/src/cot/cot.rs b/src/cot/cot.rs new file mode 100644 index 0000000..e1f8505 --- /dev/null +++ b/src/cot/cot.rs @@ -0,0 +1,109 @@ +use uuid::Uuid; +use chrono::{Duration, SecondsFormat, Utc}; + +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, +} + +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(""); + + 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(), + ); + } + + xml.push_str(""); + + return xml; + } +} diff --git a/src/cot/digital_pointer.rs b/src/cot/digital_pointer.rs new file mode 100644 index 0000000..148c476 --- /dev/null +++ b/src/cot/digital_pointer.rs @@ -0,0 +1,46 @@ +use arma_rs::{FromArma, FromArmaError}; + +use super::cot::CursorOverTime; + + +pub struct DigitalPointerPayload { + pub link_uid: String, + pub contact_callsign: String, + pub point_lat: f64, + pub point_lon: f64, + pub point_hae: f32, +} + +impl FromArma for DigitalPointerPayload { + fn from_arma(data: String) -> Result { + let (link_uid, contact_callsign, point_lat, point_lon, point_hae) = + <(String, String, f64, f64, f32)>::from_arma(data)?; + Ok(Self { + link_uid, + contact_callsign, + point_lat, + point_lon, + point_hae, + }) + } +} + +impl DigitalPointerPayload { + pub fn to_cot(&self) -> CursorOverTime { + CursorOverTime { + uuid: Some(format!("{}{}", self.link_uid.clone(), ".SPI1")), + r#type: Some("b-m-p-s-p-i".to_string()), + 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: None, + track_speed: None, + link_uid: Some(self.link_uid.clone()), + } + } +} diff --git a/src/cot/eud.rs b/src/cot/eud.rs new file mode 100644 index 0000000..67c8cde --- /dev/null +++ b/src/cot/eud.rs @@ -0,0 +1,62 @@ +use arma_rs::{FromArma, FromArmaError}; + +use super::cot::CursorOverTime; + +pub struct EudCoTPayload { + 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 EudCoTPayload { + 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 EudCoTPayload { + 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), + link_uid: None, + } + } +} diff --git a/src/cot/mod.rs b/src/cot/mod.rs new file mode 100644 index 0000000..4838ee7 --- /dev/null +++ b/src/cot/mod.rs @@ -0,0 +1,4 @@ +pub mod cot; +pub mod digital_pointer; +pub mod eud; +pub mod nato; \ No newline at end of file diff --git a/src/cot/nato.rs b/src/cot/nato.rs new file mode 100644 index 0000000..0e34325 --- /dev/null +++ b/src/cot/nato.rs @@ -0,0 +1,59 @@ +use arma_rs::{FromArma, FromArmaError}; + +use super::cot::CursorOverTime; + +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), + link_uid: None, + } + } +} diff --git a/src/cot_generator.rs b/src/cot_generator.rs deleted file mode 100644 index 1dfd98a..0000000 --- a/src/cot_generator.rs +++ /dev/null @@ -1,267 +0,0 @@ -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, - pub link_uid: 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(""); - - 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(), - ); - } - - 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), - link_uid: None, - } - } -} - -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), - link_uid: None, - } - } -} - -pub struct DigitalPointerPayload { - pub link_uid: String, - pub contact_callsign: String, - pub point_lat: f64, - pub point_lon: f64, - pub point_hae: f32, -} - -impl FromArma for DigitalPointerPayload { - fn from_arma(data: String) -> Result { - let (link_uid, contact_callsign, point_lat, point_lon, point_hae) = - <(String, String, f64, f64, f32)>::from_arma(data)?; - Ok(Self { - link_uid, - contact_callsign, - point_lat, - point_lon, - point_hae, - }) - } -} - -impl DigitalPointerPayload { - pub fn to_cot(&self) -> CursorOverTime { - CursorOverTime { - uuid: Some(format!("{}{}", self.link_uid.clone(), ".SPI1")), - r#type: Some("b-m-p-s-p-i".to_string()), - 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: None, - track_speed: None, - link_uid: Some(self.link_uid.clone()), - } - } -} diff --git a/src/cot_router.rs b/src/cot_router.rs index 27c4042..2be4d61 100644 --- a/src/cot_router.rs +++ b/src/cot_router.rs @@ -7,7 +7,7 @@ use std::sync::mpsc::{self, Receiver, Sender}; use std::sync::{Arc, Mutex}; use std::thread; -use crate::cot_generator::{DigitalPointerPayload, HumanCoTPayload, MarkerCoTPayload}; +use crate::cot; pub enum TcpCommand { SendMessage(String, Context), @@ -123,21 +123,21 @@ pub fn send_payload(ctx: Context, payload: String) -> &'static str { "Sending payload to TCP server" } -pub fn send_human_cot(ctx: Context, cursor_over_time: HumanCoTPayload) -> &'static str { +pub fn send_eud_cot(ctx: Context, cursor_over_time: cot::eud::EudCoTPayload) -> &'static str { let payload = cursor_over_time.to_cot().convert_to_xml(); send_payload(ctx, payload); - "Sending Human Cursor Over Time to TCP server" + "Sending End User Device Cursor Over Time to TCP server" } -pub fn send_marker_cot(ctx: Context, cursor_over_time: MarkerCoTPayload) -> &'static str { +pub fn send_marker_cot(ctx: Context, cursor_over_time: cot::nato::MarkerCoTPayload) -> &'static str { let payload = cursor_over_time.to_cot().convert_to_xml(); send_payload(ctx, payload); "Sending Marker Cursor Over Time to TCP server" } -pub fn send_digital_pointer_cot(ctx: Context, cursor_over_time: DigitalPointerPayload) -> &'static str { +pub fn send_digital_pointer_cot(ctx: Context, cursor_over_time: cot::digital_pointer::DigitalPointerPayload) -> &'static str { let payload = cursor_over_time.to_cot().convert_to_xml(); send_payload(ctx, payload); diff --git a/src/lib.rs b/src/lib.rs index 0679636..bb2e344 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,9 @@ mod structs; mod tests; mod websocket; mod cot_router; -mod cot_generator; mod video_stream; + +mod cot; mod utils; #[arma] @@ -45,7 +46,7 @@ pub fn init() -> Extension { Group::new() .command("start", cot_router::start) .command("send_payload", cot_router::send_payload) - .command("send_human_cot", cot_router::send_human_cot) + .command("send_eud_cot", cot_router::send_eud_cot) .command("send_marker_cot", cot_router::send_marker_cot) .command("send_digital_pointer_cot", cot_router::send_digital_pointer_cot) .command("stop", cot_router::stop)