Implemented separate TCP logger service
This commit is contained in:
@@ -58,6 +58,15 @@ struct SignalMetadata {
|
||||
sig_type: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ConnectionConfig {
|
||||
ip: String,
|
||||
tcp_port: String,
|
||||
udp_port: String,
|
||||
log_port: String,
|
||||
version: u64,
|
||||
}
|
||||
|
||||
enum InternalEvent {
|
||||
Log(LogEntry),
|
||||
Discovery(Vec<Signal>),
|
||||
@@ -65,6 +74,7 @@ enum InternalEvent {
|
||||
CommandResponse(String),
|
||||
NodeInfo(String),
|
||||
Connected,
|
||||
Disconnected,
|
||||
InternalLog(String),
|
||||
TraceRequested(String),
|
||||
ClearTrace(String),
|
||||
@@ -91,10 +101,9 @@ struct LogFilters {
|
||||
}
|
||||
|
||||
struct MarteDebugApp {
|
||||
#[allow(dead_code)]
|
||||
connected: bool,
|
||||
tcp_addr: String,
|
||||
log_addr: String,
|
||||
config: ConnectionConfig,
|
||||
shared_config: Arc<Mutex<ConnectionConfig>>,
|
||||
|
||||
signals: Vec<Signal>,
|
||||
app_tree: Option<TreeItem>,
|
||||
@@ -131,34 +140,43 @@ impl MarteDebugApp {
|
||||
let (tx_events, rx_events) = unbounded::<InternalEvent>();
|
||||
let internal_tx = tx_events.clone();
|
||||
|
||||
let tcp_addr = "127.0.0.1:8080".to_string();
|
||||
let log_addr = "127.0.0.1:8082".to_string();
|
||||
let config = ConnectionConfig {
|
||||
ip: "127.0.0.1".to_string(),
|
||||
tcp_port: "8080".to_string(),
|
||||
udp_port: "8081".to_string(),
|
||||
log_port: "8082".to_string(),
|
||||
version: 0,
|
||||
};
|
||||
|
||||
let shared_config = Arc::new(Mutex::new(config.clone()));
|
||||
let id_to_meta = Arc::new(Mutex::new(HashMap::new()));
|
||||
let traced_signals = Arc::new(Mutex::new(HashMap::new()));
|
||||
|
||||
let id_to_meta_clone = id_to_meta.clone();
|
||||
let traced_signals_clone = traced_signals.clone();
|
||||
let shared_config_cmd = shared_config.clone();
|
||||
let shared_config_log = shared_config.clone();
|
||||
let shared_config_udp = shared_config.clone();
|
||||
|
||||
let tx_events_c = tx_events.clone();
|
||||
thread::spawn(move || {
|
||||
tcp_command_worker(tcp_addr, rx_cmd_internal, tx_events_c);
|
||||
tcp_command_worker(shared_config_cmd, rx_cmd_internal, tx_events_c);
|
||||
});
|
||||
|
||||
let tx_events_log = tx_events.clone();
|
||||
thread::spawn(move || {
|
||||
tcp_log_worker(log_addr, tx_events_log);
|
||||
tcp_log_worker(shared_config_log, tx_events_log);
|
||||
});
|
||||
|
||||
let tx_events_udp = tx_events.clone();
|
||||
thread::spawn(move || {
|
||||
udp_worker(8081, id_to_meta_clone, traced_signals_clone, tx_events_udp);
|
||||
udp_worker(shared_config_udp, id_to_meta_clone, traced_signals_clone, tx_events_udp);
|
||||
});
|
||||
|
||||
Self {
|
||||
connected: false,
|
||||
tcp_addr: "127.0.0.1:8080".to_string(),
|
||||
log_addr: "127.0.0.1:8082".to_string(),
|
||||
config,
|
||||
shared_config,
|
||||
signals: Vec::new(),
|
||||
app_tree: None,
|
||||
id_to_meta,
|
||||
@@ -237,20 +255,36 @@ impl MarteDebugApp {
|
||||
}
|
||||
}
|
||||
|
||||
fn tcp_command_worker(addr: String, rx_cmd: Receiver<String>, tx_events: Sender<InternalEvent>) {
|
||||
fn tcp_command_worker(shared_config: Arc<Mutex<ConnectionConfig>>, rx_cmd: Receiver<String>, tx_events: Sender<InternalEvent>) {
|
||||
let mut current_version = 0;
|
||||
let mut current_addr = String::new();
|
||||
|
||||
loop {
|
||||
if let Ok(mut stream) = TcpStream::connect(&addr) {
|
||||
// Check for config updates
|
||||
{
|
||||
let config = shared_config.lock().unwrap();
|
||||
if config.version != current_version {
|
||||
current_version = config.version;
|
||||
current_addr = format!("{}:{}", config.ip, config.tcp_port);
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(mut stream) = TcpStream::connect(¤t_addr) {
|
||||
let _ = stream.set_nodelay(true);
|
||||
let mut reader = BufReader::new(stream.try_clone().unwrap());
|
||||
let _ = tx_events.send(InternalEvent::Connected);
|
||||
|
||||
let tx_events_inner = tx_events.clone();
|
||||
let stop_flag = Arc::new(Mutex::new(false));
|
||||
let stop_flag_reader = stop_flag.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut line = String::new();
|
||||
let mut json_acc = String::new();
|
||||
let mut in_json = false;
|
||||
|
||||
while reader.read_line(&mut line).is_ok() {
|
||||
if *stop_flag_reader.lock().unwrap() { break; }
|
||||
let trimmed = line.trim();
|
||||
if trimmed.is_empty() { line.clear(); continue; }
|
||||
|
||||
@@ -291,21 +325,47 @@ fn tcp_command_worker(addr: String, rx_cmd: Receiver<String>, tx_events: Sender<
|
||||
});
|
||||
|
||||
while let Ok(cmd) = rx_cmd.recv() {
|
||||
// Check if config changed while connected
|
||||
{
|
||||
let config = shared_config.lock().unwrap();
|
||||
if config.version != current_version {
|
||||
*stop_flag.lock().unwrap() = true;
|
||||
break; // Trigger reconnect
|
||||
}
|
||||
}
|
||||
if stream.write_all(format!("{}\n", cmd).as_bytes()).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let _ = tx_events.send(InternalEvent::Disconnected);
|
||||
}
|
||||
thread::sleep(std::time::Duration::from_secs(2));
|
||||
}
|
||||
}
|
||||
|
||||
fn tcp_log_worker(addr: String, tx_events: Sender<InternalEvent>) {
|
||||
fn tcp_log_worker(shared_config: Arc<Mutex<ConnectionConfig>>, tx_events: Sender<InternalEvent>) {
|
||||
let mut current_version = 0;
|
||||
let mut current_addr = String::new();
|
||||
|
||||
loop {
|
||||
if let Ok(stream) = TcpStream::connect(&addr) {
|
||||
{
|
||||
let config = shared_config.lock().unwrap();
|
||||
if config.version != current_version {
|
||||
current_version = config.version;
|
||||
current_addr = format!("{}:{}", config.ip, config.log_port);
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(stream) = TcpStream::connect(¤t_addr) {
|
||||
let mut reader = BufReader::new(stream);
|
||||
let mut line = String::new();
|
||||
while reader.read_line(&mut line).is_ok() {
|
||||
// Check for config update
|
||||
{
|
||||
if shared_config.lock().unwrap().version != current_version {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let trimmed = line.trim();
|
||||
if trimmed.starts_with("LOG ") {
|
||||
let parts: Vec<&str> = trimmed[4..].splitn(2, ' ').collect();
|
||||
@@ -324,14 +384,39 @@ fn tcp_log_worker(addr: String, tx_events: Sender<InternalEvent>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn udp_worker(port: u16, id_to_meta: Arc<Mutex<HashMap<u32, SignalMetadata>>>, traced_data: Arc<Mutex<HashMap<String, TraceData>>>, tx_events: Sender<InternalEvent>) {
|
||||
if let Ok(socket) = UdpSocket::bind(format!("0.0.0.0:{}", port)) {
|
||||
fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex<HashMap<u32, SignalMetadata>>>, traced_data: Arc<Mutex<HashMap<String, TraceData>>>, tx_events: Sender<InternalEvent>) {
|
||||
let mut current_version = 0;
|
||||
let mut socket: Option<UdpSocket> = None;
|
||||
|
||||
loop {
|
||||
let (ver, port) = {
|
||||
let config = shared_config.lock().unwrap();
|
||||
(config.version, config.udp_port.clone())
|
||||
};
|
||||
|
||||
if ver != current_version || socket.is_none() {
|
||||
current_version = ver;
|
||||
socket = UdpSocket::bind(format!("0.0.0.0:{}", port)).ok();
|
||||
if socket.is_none() {
|
||||
let _ = tx_events.send(InternalEvent::InternalLog(format!("UDP Bind Error on port {}", port)));
|
||||
thread::sleep(std::time::Duration::from_secs(5));
|
||||
continue;
|
||||
}
|
||||
let _ = socket.as_ref().unwrap().set_read_timeout(Some(std::time::Duration::from_millis(500)));
|
||||
}
|
||||
|
||||
let s = socket.as_ref().unwrap();
|
||||
let mut buf = [0u8; 4096];
|
||||
let start_time = std::time::Instant::now();
|
||||
let mut total_packets = 0u64;
|
||||
|
||||
loop {
|
||||
if let Ok(n) = socket.recv(&mut buf) {
|
||||
// Check for config update
|
||||
if shared_config.lock().unwrap().version != current_version {
|
||||
break; // Re-bind
|
||||
}
|
||||
|
||||
if let Ok(n) = s.recv(&mut buf) {
|
||||
total_packets += 1;
|
||||
if (total_packets % 100) == 0 {
|
||||
let _ = tx_events.send(InternalEvent::UdpStats(total_packets));
|
||||
@@ -450,9 +535,13 @@ impl eframe::App for MarteDebugApp {
|
||||
self.udp_packets = count;
|
||||
}
|
||||
InternalEvent::Connected => {
|
||||
self.connected = true;
|
||||
let _ = self.tx_cmd.send("TREE".to_string());
|
||||
let _ = self.tx_cmd.send("DISCOVER".to_string());
|
||||
}
|
||||
InternalEvent::Disconnected => {
|
||||
self.connected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,6 +573,38 @@ impl eframe::App for MarteDebugApp {
|
||||
ui.toggle_value(&mut self.show_bottom_panel, "📜 Logs");
|
||||
ui.separator();
|
||||
ui.heading("MARTe2 Debug Explorer");
|
||||
ui.separator();
|
||||
|
||||
ui.menu_button("🔌 Connection", |ui| {
|
||||
egui::Grid::new("conn_grid")
|
||||
.num_columns(2)
|
||||
.spacing([40.0, 4.0])
|
||||
.show(ui, |ui| {
|
||||
ui.label("Server IP:");
|
||||
ui.text_edit_singleline(&mut self.config.ip);
|
||||
ui.end_row();
|
||||
ui.label("Control Port (TCP):");
|
||||
ui.text_edit_singleline(&mut self.config.tcp_port);
|
||||
ui.end_row();
|
||||
ui.label("Telemetry Port (UDP):");
|
||||
ui.text_edit_singleline(&mut self.config.udp_port);
|
||||
ui.end_row();
|
||||
ui.label("Log Port (TCP):");
|
||||
ui.text_edit_singleline(&mut self.config.log_port);
|
||||
ui.end_row();
|
||||
});
|
||||
ui.separator();
|
||||
if ui.button("🔄 Apply & Reconnect").clicked() {
|
||||
self.config.version += 1;
|
||||
let mut shared = self.shared_config.lock().unwrap();
|
||||
*shared = self.config.clone();
|
||||
ui.close_menu();
|
||||
}
|
||||
});
|
||||
|
||||
let status_color = if self.connected { egui::Color32::GREEN } else { egui::Color32::RED };
|
||||
ui.label(egui::RichText::new(if self.connected { "● Online" } else { "○ Offline" }).color(status_color));
|
||||
|
||||
ui.separator();
|
||||
if ui.button("🔄 Refresh").clicked() {
|
||||
let _ = self.tx_cmd.send("TREE".to_string());
|
||||
|
||||
Reference in New Issue
Block a user