diff --git a/Cargo.toml b/Cargo.toml index cbe6b12..879eab4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,4 +28,4 @@ features = ["v4", "fast-rng", "macro-diagnostics"] [lib] name = "armatak" -crate-type = ["cdylib"] +crate-type = ["cdylib"] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 811525f..d5700cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ use arma_rs::{arma, Extension, Group}; mod structs; mod tests; -mod websocket; -mod cot_router; +mod udp_socket; +mod tcp_socket; mod video_stream; mod cot; @@ -32,24 +32,25 @@ pub fn init() -> Extension { log4rs::init_config(config).unwrap(); Extension::build() - .group("websocket", Group::new() - .command("start", websocket::start) - .command("stop", websocket::stop) - .command("message", websocket::message) - .command("location", websocket::location) - ) .command("local_ip", utils::address::get_local_address) .command("uuid", utils::uuid::get_uuid) .command("log", utils::log::log_info) + .group("udp_socket", + Group::new() + .command("start", udp_socket::start) + .command("send_payload", udp_socket::send_payload) + .command("send_gps_cot", udp_socket::send_gps_cot) + .command("stop", udp_socket::stop) + ) .group( "tcp_socket", Group::new() - .command("start", cot_router::start) - .command("send_payload", cot_router::send_payload) - .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) + .command("start", tcp_socket::start) + .command("send_payload", tcp_socket::send_payload) + .command("send_eud_cot", tcp_socket::send_eud_cot) + .command("send_marker_cot", tcp_socket::send_marker_cot) + .command("send_digital_pointer_cot", tcp_socket::send_digital_pointer_cot) + .command("stop", tcp_socket::stop) ) .group( "video_stream", diff --git a/src/udp_socket.rs b/src/udp_socket.rs new file mode 100644 index 0000000..060fb26 --- /dev/null +++ b/src/udp_socket.rs @@ -0,0 +1,127 @@ +use arma_rs::Context; +use lazy_static::lazy_static; +use log::info; +use std::net::UdpSocket; +use std::sync::mpsc::{self, Receiver, Sender}; +use std::sync::{Arc, Mutex}; +use std::thread; + +use crate::cot; + +pub enum UdpCommand { + SendMessage(String, Context), + Stop, +} + +pub struct UdpClient { + pub(crate) tx: Sender, +} + +impl UdpClient { + pub fn start(&self, address: String, rx: Receiver, ctx: Context) { + if let Some(ref client) = *UDP_CLIENT.lock().unwrap() { + client.stop(); + } + + let udp_address = address.clone(); + + thread::spawn(move || { + let socket = match UdpSocket::bind(udp_address) { + Ok(s) => s, + Err(e) => { + let _ = ctx.callback_data( + "UDP SOCKET ERROR", + "Failed to bind UDP socket", + e.to_string(), + ); + info!("Failed to bind UDP socket: {}", e); + return; + } + }; + + let _ = ctx.callback_data("UDP SOCKET", "UDP Socket ready", address.clone()); + + let mut running = true; + while running { + match rx.recv() { + Ok(UdpCommand::SendMessage(message, context)) => { + if let Err(e) = socket.send_to(message.as_bytes(), &address) { + info!("Failed to send UDP message: {}", e); + let _ = context.callback_data( + "UDP SOCKET ERROR", + "Failed to send UDP message", + e.to_string(), + ); + } + } + Ok(UdpCommand::Stop) => { + running = false; + info!("Stopping UDP client."); + } + Err(error) => { + info!("Error receiving command: {}", error.to_string()); + } + } + } + }); + } + + pub fn send_payload(&self, context: Context, payload: String) { + let tx = self.tx.clone(); + thread::spawn(move || { + tx.send(UdpCommand::SendMessage(payload, context)).unwrap(); + }); + } + + pub fn stop(&self) { + let tx = self.tx.clone(); + thread::spawn(move || { + tx.send(UdpCommand::Stop).unwrap(); + }); + } +} + +lazy_static! { + static ref UDP_CLIENT: Arc>> = Arc::new(Mutex::new(None)); +} + +pub fn start(ctx: Context, address: String) -> &'static str { + let (tx, rx): (Sender, Receiver) = mpsc::channel(); + + let client = UdpClient { tx }; + client.start(address, rx, ctx); + + let mut client_guard = UDP_CLIENT.lock().unwrap(); + *client_guard = Some(client); + + "Starting UDP Client" +} + +pub fn send_payload(ctx: Context, payload: String) -> &'static str { + if let Some(ref client) = *UDP_CLIENT.lock().unwrap() { + client.send_payload(ctx, payload); + } else { + let _ = ctx.callback_null("UDP SOCKET ERROR", "UDP Client is not running"); + info!("UDP client is not running."); + } + + "Sending payload to UDP server" +} + +pub fn send_gps_cot(ctx: Context, cursor_over_time: cot::gps::ExternalPositionPayload) -> &'static str { + let payload = cursor_over_time.to_cot().convert_to_xml(); + send_payload(ctx, payload); + + "Sending GPS Cursor Over Time to UDP server" +} + +pub fn stop(ctx: Context) -> &'static str { + if let Some(ref client) = *UDP_CLIENT.lock().unwrap() { + client.stop(); + let _ = ctx.callback_null("UDP SOCKET", "UDP client stopped"); + } else { + let _ = ctx.callback_null("UDP SOCKET ERROR", "UDP client is not running"); + } + + "Stopping UDP Client" +}