mirror of
https://github.com/valmojr/armatak.git
synced 2026-06-13 13:53:28 +00:00
formatted some rust docs
This commit is contained in:
@@ -131,8 +131,8 @@ impl UasPlatformCoTPayload {
|
|||||||
None => (escape_xml(&self.vehicle_type_tag), None),
|
None => (escape_xml(&self.vehicle_type_tag), None),
|
||||||
};
|
};
|
||||||
let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);
|
let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);
|
||||||
let stale =
|
let stale = (Utc::now() + Duration::milliseconds(3500))
|
||||||
(Utc::now() + Duration::milliseconds(3500)).to_rfc3339_opts(SecondsFormat::Millis, true);
|
.to_rfc3339_opts(SecondsFormat::Millis, true);
|
||||||
|
|
||||||
let mut xml = String::new();
|
let mut xml = String::new();
|
||||||
xml.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
xml.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
||||||
@@ -153,8 +153,7 @@ impl UasPlatformCoTPayload {
|
|||||||
xml.push_str("<_uastool extendedCot=\"true\" activeRoute=\"false\"/>");
|
xml.push_str("<_uastool extendedCot=\"true\" activeRoute=\"false\"/>");
|
||||||
xml.push_str(&format!(
|
xml.push_str(&format!(
|
||||||
"<track course=\"{}\" slope=\"0.0\" speed=\"{}\"/>",
|
"<track course=\"{}\" slope=\"0.0\" speed=\"{}\"/>",
|
||||||
self.track_course,
|
self.track_course, self.track_speed,
|
||||||
self.track_speed,
|
|
||||||
));
|
));
|
||||||
xml.push_str(&format!(
|
xml.push_str(&format!(
|
||||||
"<sensor elevation=\"{}\" vfov=\"{}\" north=\"0.0\" roll=\"0.0\" range=\"{}\" azimuth=\"{}\" fov=\"{}\" type=\"r-e\" version=\"0.6\"/>",
|
"<sensor elevation=\"{}\" vfov=\"{}\" north=\"0.0\" roll=\"0.0\" range=\"{}\" azimuth=\"{}\" fov=\"{}\" type=\"r-e\" version=\"0.6\"/>",
|
||||||
@@ -186,7 +185,10 @@ impl UasPlatformCoTPayload {
|
|||||||
} else {
|
} else {
|
||||||
xml.push_str("<__video></__video>");
|
xml.push_str("<__video></__video>");
|
||||||
}
|
}
|
||||||
xml.push_str(&format!("<link uid=\"{}\" type=\"a-f-G-U-C\" relation=\"p-p\" />", link_uid));
|
xml.push_str(&format!(
|
||||||
|
"<link uid=\"{}\" type=\"a-f-G-U-C\" relation=\"p-p\" />",
|
||||||
|
link_uid
|
||||||
|
));
|
||||||
xml.push_str("</detail></event>");
|
xml.push_str("</detail></event>");
|
||||||
xml
|
xml
|
||||||
}
|
}
|
||||||
@@ -326,5 +328,3 @@ impl UasSensorCoTPayload {
|
|||||||
xml
|
xml
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ fn parse_video_url(url: &str) -> Option<(String, String, String, String)> {
|
|||||||
Some((authority, path)) => (authority, format!("/{}", path)),
|
Some((authority, path)) => (authority, format!("/{}", path)),
|
||||||
None => (rest, String::new()),
|
None => (rest, String::new()),
|
||||||
};
|
};
|
||||||
let host_port = authority.rsplit_once('@').map_or(authority, |(_, host_port)| host_port);
|
let host_port = authority
|
||||||
|
.rsplit_once('@')
|
||||||
|
.map_or(authority, |(_, host_port)| host_port);
|
||||||
let (address, port) = host_port.rsplit_once(':')?;
|
let (address, port) = host_port.rsplit_once(':')?;
|
||||||
|
|
||||||
if protocol.is_empty() || address.is_empty() || port.is_empty() {
|
if protocol.is_empty() || address.is_empty() || port.is_empty() {
|
||||||
@@ -35,10 +37,7 @@ pub fn video_detail_xml(video_url: &str, uid: &str, callsign: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let Some((protocol, address, port, path)) = parse_video_url(trimmed_url) else {
|
let Some((protocol, address, port, path)) = parse_video_url(trimmed_url) else {
|
||||||
return format!(
|
return format!("<__video url=\"{}\"/>", escape_xml_attribute(trimmed_url));
|
||||||
"<__video url=\"{}\"/>",
|
|
||||||
escape_xml_attribute(trimmed_url)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ mod mdns;
|
|||||||
mod structs;
|
mod structs;
|
||||||
mod tcp;
|
mod tcp;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
mod uas;
|
||||||
mod udp_socket;
|
mod udp_socket;
|
||||||
mod video_stream;
|
mod video_stream;
|
||||||
|
|
||||||
|
|||||||
32
src/mdns.rs
32
src/mdns.rs
@@ -23,7 +23,13 @@ fn detect_local_ipv4() -> Result<Ipv4Addr, String> {
|
|||||||
fn sanitize_label(value: &str, fallback: &str) -> String {
|
fn sanitize_label(value: &str, fallback: &str) -> String {
|
||||||
let mut sanitized = value
|
let mut sanitized = value
|
||||||
.chars()
|
.chars()
|
||||||
.map(|c| if c.is_ascii_alphanumeric() || c == '-' { c } else { '-' })
|
.map(|c| {
|
||||||
|
if c.is_ascii_alphanumeric() || c == '-' {
|
||||||
|
c
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
.trim_matches('-')
|
.trim_matches('-')
|
||||||
.to_string();
|
.to_string();
|
||||||
@@ -67,7 +73,13 @@ fn push_record(buf: &mut Vec<u8>, name: &str, rr_type: u16, rr_class: u16, ttl:
|
|||||||
buf.extend_from_slice(rdata);
|
buf.extend_from_slice(rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_mdns_packet(instance_name: &str, host_name: &str, ip: Ipv4Addr, port: u16, video_uri: &str) -> Vec<u8> {
|
fn build_mdns_packet(
|
||||||
|
instance_name: &str,
|
||||||
|
host_name: &str,
|
||||||
|
ip: Ipv4Addr,
|
||||||
|
port: u16,
|
||||||
|
video_uri: &str,
|
||||||
|
) -> Vec<u8> {
|
||||||
let service_type = "_mavlink._udp.local";
|
let service_type = "_mavlink._udp.local";
|
||||||
let instance_fqdn = format!("{}.{}", instance_name, service_type);
|
let instance_fqdn = format!("{}.{}", instance_name, service_type);
|
||||||
let host_fqdn = format!("{}.local", host_name);
|
let host_fqdn = format!("{}.local", host_name);
|
||||||
@@ -122,7 +134,11 @@ pub fn start_uas_advertisement(
|
|||||||
let local_ip = match detect_local_ipv4() {
|
let local_ip = match detect_local_ipv4() {
|
||||||
Ok(ip) => ip,
|
Ok(ip) => ip,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
let _ = ctx.callback_data("MDNS ERROR", "Failed to determine local IPv4", error.clone());
|
let _ = ctx.callback_data(
|
||||||
|
"MDNS ERROR",
|
||||||
|
"Failed to determine local IPv4",
|
||||||
|
error.clone(),
|
||||||
|
);
|
||||||
return "mdns local IPv4 error";
|
return "mdns local IPv4 error";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -161,7 +177,10 @@ pub fn start_uas_advertisement(
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
match socket.send_to(&packet, multicast_addr) {
|
match socket.send_to(&packet, multicast_addr) {
|
||||||
Ok(size) => info!("Sent mDNS UAS advertisement ({} bytes) to {}", size, multicast_addr),
|
Ok(size) => info!(
|
||||||
|
"Sent mDNS UAS advertisement ({} bytes) to {}",
|
||||||
|
size, multicast_addr
|
||||||
|
),
|
||||||
Err(error) => info!("Failed sending mDNS UAS advertisement: {}", error),
|
Err(error) => info!("Failed sending mDNS UAS advertisement: {}", error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +191,10 @@ pub fn start_uas_advertisement(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Stopped mDNS UAS advertisement for instance={}", safe_instance);
|
info!(
|
||||||
|
"Stopped mDNS UAS advertisement for instance={}",
|
||||||
|
safe_instance
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let _ = ctx.callback_data(
|
let _ = ctx.callback_data(
|
||||||
|
|||||||
@@ -54,17 +54,15 @@ fn send_over_stream(
|
|||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let message_len = message.len();
|
let message_len = message.len();
|
||||||
info!("Sending TCP payload ({} bytes)", message_len);
|
info!("Sending TCP payload ({} bytes)", message_len);
|
||||||
stream
|
stream.write_message(message.as_bytes()).map_err(|e| {
|
||||||
.write_message(message.as_bytes())
|
let message = e.to_string();
|
||||||
.map_err(|e| {
|
let _ = context.callback_data(
|
||||||
let message = e.to_string();
|
"TCP SOCKET ERROR",
|
||||||
let _ = context.callback_data(
|
"TAK Socket disconnected",
|
||||||
"TCP SOCKET ERROR",
|
message.clone(),
|
||||||
"TAK Socket disconnected",
|
);
|
||||||
message.clone(),
|
message
|
||||||
);
|
})
|
||||||
message
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_pending_messages(
|
fn flush_pending_messages(
|
||||||
@@ -145,10 +143,14 @@ impl TcpClient {
|
|||||||
let mut pending_messages: VecDeque<(String, Context)> = VecDeque::new();
|
let mut pending_messages: VecDeque<(String, Context)> = VecDeque::new();
|
||||||
let (connect_tx, connect_rx) = mpsc::channel();
|
let (connect_tx, connect_rx) = mpsc::channel();
|
||||||
|
|
||||||
info!("TCP worker thread started with config: {}", config_description);
|
info!(
|
||||||
|
"TCP worker thread started with config: {}",
|
||||||
|
config_description
|
||||||
|
);
|
||||||
|
|
||||||
let tcp_thread = thread::spawn(move || {
|
let tcp_thread = thread::spawn(move || {
|
||||||
let connect_result = panic::catch_unwind(AssertUnwindSafe(|| connect_stream(&config)));
|
let connect_result =
|
||||||
|
panic::catch_unwind(AssertUnwindSafe(|| connect_stream(&config)));
|
||||||
|
|
||||||
match connect_result {
|
match connect_result {
|
||||||
Ok(Ok(stream)) => {
|
Ok(Ok(stream)) => {
|
||||||
@@ -184,7 +186,8 @@ impl TcpClient {
|
|||||||
match &mut state {
|
match &mut state {
|
||||||
ConnectionState::Connected => {
|
ConnectionState::Connected => {
|
||||||
if let Some(stream) = connection.as_mut() {
|
if let Some(stream) = connection.as_mut() {
|
||||||
if let Err(error) = send_over_stream(stream, &context, message) {
|
if let Err(error) = send_over_stream(stream, &context, message)
|
||||||
|
{
|
||||||
info!("Failed to send message: {}", error);
|
info!("Failed to send message: {}", error);
|
||||||
state = ConnectionState::Failed(error);
|
state = ConnectionState::Failed(error);
|
||||||
connection = None;
|
connection = None;
|
||||||
|
|||||||
@@ -50,10 +50,7 @@ pub fn send_uas_platform_cot(
|
|||||||
"Sending UAS Platform main CoT to TCP server"
|
"Sending UAS Platform main CoT to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_uas_video_cot(
|
pub fn send_uas_video_cot(ctx: Context, payload: cot::uas::UasVideoCoTPayload) -> &'static str {
|
||||||
ctx: Context,
|
|
||||||
payload: cot::uas::UasVideoCoTPayload,
|
|
||||||
) -> &'static str {
|
|
||||||
let xml = payload.to_xml();
|
let xml = payload.to_xml();
|
||||||
if !xml.is_empty() {
|
if !xml.is_empty() {
|
||||||
send_payload(ctx, xml);
|
send_payload(ctx, xml);
|
||||||
@@ -62,10 +59,7 @@ pub fn send_uas_video_cot(
|
|||||||
"Sending UAS Video (b-i-v) CoT to TCP server"
|
"Sending UAS Video (b-i-v) CoT to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_uas_sensor_cot(
|
pub fn send_uas_sensor_cot(ctx: Context, payload: cot::uas::UasSensorCoTPayload) -> &'static str {
|
||||||
ctx: Context,
|
|
||||||
payload: cot::uas::UasSensorCoTPayload,
|
|
||||||
) -> &'static str {
|
|
||||||
let xml = payload.to_xml();
|
let xml = payload.to_xml();
|
||||||
send_payload(ctx, xml);
|
send_payload(ctx, xml);
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use std::fs::File;
|
|||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::net::{SocketAddr, TcpStream, ToSocketAddrs};
|
use std::net::{SocketAddr, TcpStream, ToSocketAddrs};
|
||||||
use std::time::Duration;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::tcp::transport::TransportStream;
|
use crate::tcp::transport::TransportStream;
|
||||||
|
|
||||||
@@ -65,7 +65,12 @@ fn resolve_address(address: &str) -> Result<SocketAddr, String> {
|
|||||||
.to_socket_addrs()
|
.to_socket_addrs()
|
||||||
.map_err(|e| format!("failed to resolve {}: {}", address, e))?
|
.map_err(|e| format!("failed to resolve {}: {}", address, e))?
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| format!("failed to resolve {}: no socket addresses returned", address))
|
.ok_or_else(|| {
|
||||||
|
format!(
|
||||||
|
"failed to resolve {}: no socket addresses returned",
|
||||||
|
address
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_tcp(address: &str) -> Result<TcpStream, String> {
|
fn connect_tcp(address: &str) -> Result<TcpStream, String> {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair, PKCS_RSA_SHA256};
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair, PKCS_RSA_SHA256};
|
||||||
use reqwest::blocking::Client;
|
use reqwest::blocking::Client;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@@ -198,10 +198,7 @@ pub fn enroll_and_connect(
|
|||||||
};
|
};
|
||||||
info!(
|
info!(
|
||||||
"Starting enroll_and_connect for host={} enroll_port={} server_name={} client_uid={}",
|
"Starting enroll_and_connect for host={} enroll_port={} server_name={} client_uid={}",
|
||||||
host,
|
host, enroll_port, server_name, normalized_client_uid
|
||||||
enroll_port,
|
|
||||||
server_name,
|
|
||||||
normalized_client_uid
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let enrollment_config = fetch_enrollment_config(host, enroll_port)?;
|
let enrollment_config = fetch_enrollment_config(host, enroll_port)?;
|
||||||
|
|||||||
@@ -35,7 +35,12 @@ fn connect_plain(address: &str) -> Result<TransportStream, String> {
|
|||||||
.to_socket_addrs()
|
.to_socket_addrs()
|
||||||
.map_err(|e| format!("failed to resolve {}: {}", address, e))?
|
.map_err(|e| format!("failed to resolve {}: {}", address, e))?
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| format!("failed to resolve {}: no socket addresses returned", address))?;
|
.ok_or_else(|| {
|
||||||
|
format!(
|
||||||
|
"failed to resolve {}: no socket addresses returned",
|
||||||
|
address
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Opening plain TCP connection to {} (resolved={}) with timeout {:?}",
|
"Opening plain TCP connection to {} (resolved={}) with timeout {:?}",
|
||||||
|
|||||||
@@ -70,7 +70,10 @@ pub fn start_stream(
|
|||||||
let rtsp_url = if username.is_empty() || password.is_empty() {
|
let rtsp_url = if username.is_empty() || password.is_empty() {
|
||||||
format!("rtsp://{}:{}/{}", address, port, stream_path)
|
format!("rtsp://{}:{}/{}", address, port, stream_path)
|
||||||
} else {
|
} else {
|
||||||
format!("rtsp://{}:{}@{}:{}/{}", username, password, address, port, stream_path)
|
format!(
|
||||||
|
"rtsp://{}:{}@{}:{}/{}",
|
||||||
|
username, password, address, port, stream_path
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut cmd = Command::new("ffmpeg");
|
let mut cmd = Command::new("ffmpeg");
|
||||||
|
|||||||
Reference in New Issue
Block a user