better state updates; moved ui elements; moved broke coord mod into 2 files
This commit is contained in:
parent
1fb0a279c8
commit
8164eca473
7 changed files with 340 additions and 284 deletions
250
src/coordinator/coord_state.rs
Normal file
250
src/coordinator/coord_state.rs
Normal file
|
@ -0,0 +1,250 @@
|
|||
use std::pin::Pin;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use std::time::Instant;
|
||||
|
||||
use async_channel::{Receiver, Sender};
|
||||
use futures_util::{stream::SplitSink, SinkExt, StreamExt};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::runtime::Handle;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio_tungstenite::{connect_async, tungstenite::Message, MaybeTlsStream, WebSocketStream};
|
||||
use tracing::{debug, error, info, instrument};
|
||||
|
||||
use crate::config::AppConfig;
|
||||
use crate::coordinator::socket_listen;
|
||||
use crate::remote_sources::TrackerState;
|
||||
use crate::{gstreamer_pipeline, remote_sources};
|
||||
use crate::{joystick_source::joystick_loop, ui::GuiUpdate};
|
||||
|
||||
use super::remote_video_processor::remote_video_loop;
|
||||
use super::{ApplicationEvent, ConnectionType};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SocketState {
|
||||
pub is_connected: AtomicBool,
|
||||
pub stay_connected: AtomicBool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CoordState<'a> {
|
||||
pub settings: Arc<RwLock<AppConfig>>,
|
||||
|
||||
pub sck_outbound: Option<SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>>,
|
||||
pub remote_sources_state: Arc<SocketState>,
|
||||
pub stay_alive_sck_recvr: Arc<AtomicBool>,
|
||||
pub joystick_loop_alive: Arc<AtomicBool>,
|
||||
|
||||
pub current_priority: ConnectionType,
|
||||
pub last_update_of_priority: Instant,
|
||||
|
||||
pub mec: Pin<&'a mut Receiver<ApplicationEvent>>,
|
||||
pub to_mec: Sender<ApplicationEvent>,
|
||||
pub to_gui: Sender<GuiUpdate>,
|
||||
pub rt: Handle,
|
||||
|
||||
pub pipeline: gstreamer_pipeline::WebcamPipeline,
|
||||
|
||||
pub tracker_state: Arc<Mutex<TrackerState>>,
|
||||
pub tracker_connection_state: Arc<SocketState>,
|
||||
}
|
||||
|
||||
impl<'a> CoordState<'a> {
|
||||
pub fn new(
|
||||
mec: Pin<&'a mut Receiver<ApplicationEvent>>,
|
||||
to_mec: Sender<ApplicationEvent>,
|
||||
to_gui: Sender<GuiUpdate>,
|
||||
rt: Handle,
|
||||
tracker_state: Arc<Mutex<TrackerState>>,
|
||||
settings: Arc<RwLock<AppConfig>>,
|
||||
) -> Self {
|
||||
let this = CoordState {
|
||||
settings,
|
||||
|
||||
sck_outbound: None,
|
||||
stay_alive_sck_recvr: Arc::new(AtomicBool::new(false)),
|
||||
remote_sources_state: Arc::new(SocketState {
|
||||
stay_connected: AtomicBool::new(false),
|
||||
is_connected: AtomicBool::new(false),
|
||||
}),
|
||||
joystick_loop_alive: Arc::new(AtomicBool::new(false)),
|
||||
|
||||
current_priority: ConnectionType::Local,
|
||||
last_update_of_priority: Instant::now(),
|
||||
|
||||
mec,
|
||||
to_mec,
|
||||
to_gui,
|
||||
rt,
|
||||
|
||||
pipeline: gstreamer_pipeline::WebcamPipeline::new().unwrap(),
|
||||
|
||||
tracker_state,
|
||||
tracker_connection_state: Arc::new(SocketState {
|
||||
stay_connected: AtomicBool::new(false),
|
||||
is_connected: AtomicBool::new(false),
|
||||
}),
|
||||
};
|
||||
this
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn socket_send(&mut self, message: Message) {
|
||||
if let Some(mut socket) = self.sck_outbound.take() {
|
||||
if let Err(e) = socket.send(message).await {
|
||||
error!("There was an error sending to the socket: {:#?}", e);
|
||||
} else {
|
||||
self.sck_outbound = Some(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn socket_connected(&self) -> bool {
|
||||
self.sck_outbound.is_some()
|
||||
}
|
||||
|
||||
pub async fn socket_start(&mut self) {
|
||||
self.stay_alive_sck_recvr.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Err(e) = self.to_gui.send(GuiUpdate::SocketConnecting).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
}
|
||||
|
||||
let conn_string: String = {
|
||||
let read_settings = self.settings.read().await;
|
||||
|
||||
format!(
|
||||
"ws://{}:{}",
|
||||
read_settings.camera_ip,
|
||||
read_settings.camera_port.to_string()
|
||||
)
|
||||
};
|
||||
|
||||
match connect_async(conn_string).await {
|
||||
Ok((val, _)) => {
|
||||
info!("Socket connection to camera made successfully");
|
||||
|
||||
let (outbound, inbound) = val.split();
|
||||
self.rt.spawn(socket_listen(
|
||||
self.to_mec.clone(),
|
||||
self.stay_alive_sck_recvr.clone(),
|
||||
inbound,
|
||||
));
|
||||
self.sck_outbound = Some(outbound);
|
||||
|
||||
if let Err(e) = self.to_gui.send(GuiUpdate::SocketConnected).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
error!("Couldn't connect to URL!");
|
||||
if let Err(e) = self.to_gui.send(GuiUpdate::SocketDisconnected).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn socket_close(&mut self) {
|
||||
debug!("Cleaning up camera socket state");
|
||||
|
||||
if let Some(mut socket) = self.sck_outbound.take() {
|
||||
if let Err(e) = socket.close().await {
|
||||
error!("Couldn't close socket during shutdown: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = self.to_gui.send(GuiUpdate::SocketDisconnected).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
}
|
||||
|
||||
self.stay_alive_sck_recvr.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
pub async fn start_video_loop(&mut self) {
|
||||
let conn_string: String = {
|
||||
let read_settings = self.settings.read().await;
|
||||
|
||||
format!(
|
||||
"ws://{}:{}",
|
||||
read_settings.tracker_ip,
|
||||
read_settings.tracker_port.to_string()
|
||||
)
|
||||
};
|
||||
|
||||
self.rt.spawn(remote_video_loop(
|
||||
conn_string,
|
||||
self.pipeline.sink_frame.clone(),
|
||||
self.to_mec.clone(),
|
||||
self.tracker_connection_state.clone(),
|
||||
self.tracker_state.clone(),
|
||||
self.rt.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
pub async fn check_states(&mut self) {
|
||||
// This one needs to always be alive, and restart after a crash
|
||||
if !self.joystick_loop_alive.load(Ordering::SeqCst) {
|
||||
info!("Restarting joystick loop");
|
||||
self.rt.spawn(joystick_loop(
|
||||
self.to_mec.clone(),
|
||||
self.joystick_loop_alive.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
// If tracker state is not connected, and it should be
|
||||
if !self
|
||||
.tracker_connection_state
|
||||
.is_connected
|
||||
.load(Ordering::SeqCst)
|
||||
&& self
|
||||
.tracker_connection_state
|
||||
.stay_connected
|
||||
.load(Ordering::SeqCst)
|
||||
{
|
||||
self.start_video_loop().await;
|
||||
}
|
||||
|
||||
//
|
||||
if self
|
||||
.remote_sources_state
|
||||
.stay_connected
|
||||
.load(Ordering::SeqCst)
|
||||
&& !self
|
||||
.remote_sources_state
|
||||
.is_connected
|
||||
.load(Ordering::SeqCst)
|
||||
{
|
||||
info!("Restarting socket server");
|
||||
self.rt.spawn(remote_sources::start_socketserver(
|
||||
self.rt.clone(),
|
||||
self.to_mec.clone(),
|
||||
self.remote_sources_state.clone(),
|
||||
self.tracker_state.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
// if stay alive is false, and there is a connection, kill it
|
||||
if !self.stay_alive_sck_recvr.load(Ordering::SeqCst) && self.sck_outbound.is_some() {
|
||||
self.socket_close().await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn close(&mut self) {
|
||||
info!("closing coord state");
|
||||
self.tracker_connection_state
|
||||
.stay_connected
|
||||
.store(false, Ordering::SeqCst);
|
||||
self.socket_close().await;
|
||||
|
||||
self.joystick_loop_alive.store(false, Ordering::SeqCst);
|
||||
self.remote_sources_state
|
||||
.stay_connected
|
||||
.store(false, Ordering::SeqCst);
|
||||
self.to_gui.close();
|
||||
self.mec.close();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use std::pin::{pin, Pin};
|
||||
use std::pin::pin;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
|
@ -7,27 +7,23 @@ use std::sync::{
|
|||
use std::time::{Duration, Instant};
|
||||
|
||||
use async_channel::{Receiver, Sender};
|
||||
use futures_util::{
|
||||
stream::{SplitSink, SplitStream},
|
||||
SinkExt, StreamExt,
|
||||
};
|
||||
use futures_util::{stream::SplitStream, StreamExt};
|
||||
use gstreamer::prelude::ElementExt;
|
||||
use gstreamer::State;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::runtime::Handle;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio_tungstenite::{connect_async, tungstenite::Message, MaybeTlsStream, WebSocketStream};
|
||||
use tokio_tungstenite::{tungstenite::Message, MaybeTlsStream, WebSocketStream};
|
||||
use tracing::{debug, error, info, instrument};
|
||||
|
||||
mod coord_state;
|
||||
mod process_box_string;
|
||||
mod remote_video_processor;
|
||||
|
||||
use crate::config::AppConfig;
|
||||
use crate::remote_sources::TrackerState;
|
||||
use crate::{gstreamer_pipeline, remote_sources};
|
||||
use crate::{joystick_source::joystick_loop, ui::GuiUpdate};
|
||||
|
||||
use self::remote_video_processor::remote_video_loop;
|
||||
use crate::ui::GuiUpdate;
|
||||
pub use coord_state::{CoordState, SocketState};
|
||||
|
||||
const PRIORITY_TIMEOUT: Duration = Duration::from_secs(2);
|
||||
|
||||
|
@ -45,230 +41,12 @@ pub enum ConnectionType {
|
|||
}
|
||||
|
||||
pub enum ApplicationEvent {
|
||||
StartCameraSocket,
|
||||
CameraConnectionPress,
|
||||
SocketMessage(Message),
|
||||
MoveEvent(MoveEvent, ConnectionType),
|
||||
EnableAutomatic(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SocketState {
|
||||
pub is_connected: AtomicBool,
|
||||
pub stay_connected: AtomicBool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CoordState<'a> {
|
||||
pub settings: Arc<RwLock<AppConfig>>,
|
||||
|
||||
pub sck_outbound: Option<SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>>,
|
||||
pub keep_remote_sources_alive: Arc<AtomicBool>,
|
||||
pub sck_alive_recvr: Arc<AtomicBool>,
|
||||
pub joystick_loop_alive: Arc<AtomicBool>,
|
||||
|
||||
pub current_priority: ConnectionType,
|
||||
pub last_update_of_priority: Instant,
|
||||
|
||||
pub mec: Pin<&'a mut Receiver<ApplicationEvent>>,
|
||||
pub to_mec: Sender<ApplicationEvent>,
|
||||
pub to_gui: Sender<GuiUpdate>,
|
||||
pub rt: Handle,
|
||||
|
||||
pub pipeline: gstreamer_pipeline::WebcamPipeline,
|
||||
|
||||
pub tracker_state: Arc<Mutex<TrackerState>>,
|
||||
pub tracker_connection_state: Arc<SocketState>,
|
||||
}
|
||||
|
||||
impl<'a> CoordState<'a> {
|
||||
pub fn new(
|
||||
mec: Pin<&'a mut Receiver<ApplicationEvent>>,
|
||||
to_mec: Sender<ApplicationEvent>,
|
||||
to_gui: Sender<GuiUpdate>,
|
||||
rt: Handle,
|
||||
tracker_state: Arc<Mutex<TrackerState>>,
|
||||
settings: Arc<RwLock<AppConfig>>,
|
||||
) -> Self {
|
||||
let this = CoordState {
|
||||
settings,
|
||||
|
||||
sck_outbound: None,
|
||||
sck_alive_recvr: Arc::new(AtomicBool::new(false)),
|
||||
keep_remote_sources_alive: Arc::new(AtomicBool::new(false)),
|
||||
joystick_loop_alive: Arc::new(AtomicBool::new(false)),
|
||||
|
||||
current_priority: ConnectionType::Local,
|
||||
last_update_of_priority: Instant::now(),
|
||||
|
||||
mec,
|
||||
to_mec,
|
||||
to_gui,
|
||||
rt,
|
||||
|
||||
pipeline: gstreamer_pipeline::WebcamPipeline::new().unwrap(),
|
||||
|
||||
tracker_state,
|
||||
tracker_connection_state: Arc::new(SocketState {
|
||||
stay_connected: AtomicBool::new(false),
|
||||
is_connected: AtomicBool::new(false),
|
||||
}),
|
||||
};
|
||||
this
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn socket_send(&mut self, message: Message) {
|
||||
if let Some(mut socket) = self.sck_outbound.take() {
|
||||
if let Err(e) = socket.send(message).await {
|
||||
error!("There was an error sending to the socket: {:#?}", e);
|
||||
} else {
|
||||
self.sck_outbound = Some(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn socket_connected(&self) -> bool {
|
||||
self.sck_outbound.is_some()
|
||||
}
|
||||
|
||||
async fn socket_start(&mut self) {
|
||||
debug!("Starting socket");
|
||||
self.sck_alive_recvr.store(true, Ordering::SeqCst);
|
||||
|
||||
if let Err(e) = self.to_gui.send(GuiUpdate::SocketConnecting).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
}
|
||||
|
||||
let conn_string: String = {
|
||||
let read_settings = self.settings.read().await;
|
||||
|
||||
format!(
|
||||
"ws://{}:{}",
|
||||
read_settings.camera_ip,
|
||||
read_settings.camera_port.to_string()
|
||||
)
|
||||
};
|
||||
|
||||
match connect_async(conn_string).await {
|
||||
Ok((val, _)) => {
|
||||
info!("Socket connection to camera made successfully");
|
||||
|
||||
let (outbound, inbound) = val.split();
|
||||
self.rt.spawn(socket_listen(
|
||||
self.to_mec.clone(),
|
||||
self.sck_alive_recvr.clone(),
|
||||
inbound,
|
||||
));
|
||||
self.sck_outbound = Some(outbound);
|
||||
|
||||
if let Err(e) = self.to_gui.send(GuiUpdate::SocketConnected).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
error!("Couldn't connect to URL!");
|
||||
if let Err(e) = self.to_gui.send(GuiUpdate::SocketDisconnected).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn socket_close(&mut self) {
|
||||
if let Some(mut socket) = self.sck_outbound.take() {
|
||||
if let Err(e) = socket.close().await {
|
||||
error!("Couldnt' close socket during shutdown: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = self.to_gui.send(GuiUpdate::SocketDisconnected).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
}
|
||||
self.sck_alive_recvr.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
pub async fn start_video_loop(&mut self) {
|
||||
let conn_string: String = {
|
||||
let read_settings = self.settings.read().await;
|
||||
|
||||
format!(
|
||||
"ws://{}:{}",
|
||||
read_settings.tracker_ip,
|
||||
read_settings.tracker_port.to_string()
|
||||
)
|
||||
};
|
||||
|
||||
self.rt.spawn(remote_video_loop(
|
||||
conn_string,
|
||||
self.pipeline.sink_frame.clone(),
|
||||
self.to_mec.clone(),
|
||||
self.tracker_connection_state.clone(),
|
||||
self.tracker_state.clone(),
|
||||
self.rt.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
pub async fn check_states(&mut self) {
|
||||
if !self.joystick_loop_alive.load(Ordering::SeqCst) {
|
||||
info!("Restarting joystick loop");
|
||||
self.rt.spawn(joystick_loop(
|
||||
self.to_mec.clone(),
|
||||
self.joystick_loop_alive.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
if !self
|
||||
.tracker_connection_state
|
||||
.is_connected
|
||||
.load(Ordering::SeqCst)
|
||||
{
|
||||
if self
|
||||
.tracker_connection_state
|
||||
.stay_connected
|
||||
.load(Ordering::SeqCst)
|
||||
{
|
||||
self.start_video_loop().await;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.keep_remote_sources_alive.load(Ordering::SeqCst) {
|
||||
info!("Restarting socket server");
|
||||
self.keep_remote_sources_alive.store(true, Ordering::SeqCst);
|
||||
self.rt.spawn(remote_sources::start_socketserver(
|
||||
self.rt.clone(),
|
||||
self.to_mec.clone(),
|
||||
self.keep_remote_sources_alive.clone(),
|
||||
self.tracker_state.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
if !self.sck_alive_recvr.load(Ordering::SeqCst) || self.sck_outbound.is_none() {
|
||||
self.socket_close().await;
|
||||
|
||||
if let Err(e) = self.to_gui.send(GuiUpdate::SocketDisconnected).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
}
|
||||
} else if let Err(e) = self.to_gui.send(GuiUpdate::SocketConnected).await {
|
||||
error!("Cannot send message to gui thread: {e}");
|
||||
self.close().await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn close(&mut self) {
|
||||
info!("closing coord state");
|
||||
self.tracker_connection_state
|
||||
.stay_connected
|
||||
.store(false, Ordering::SeqCst);
|
||||
self.socket_close().await;
|
||||
|
||||
self.joystick_loop_alive.store(false, Ordering::SeqCst);
|
||||
self.keep_remote_sources_alive
|
||||
.store(false, Ordering::SeqCst);
|
||||
self.to_gui.close();
|
||||
self.mec.close();
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn start_coordinator(
|
||||
// Main_Event_Channel
|
||||
|
@ -307,16 +85,14 @@ pub async fn start_coordinator(
|
|||
state.check_states().await;
|
||||
|
||||
match msg {
|
||||
ApplicationEvent::StartCameraSocket => {
|
||||
state.socket_start().await;
|
||||
ApplicationEvent::CameraConnectionPress => {
|
||||
if state.socket_connected() {
|
||||
state.socket_close().await;
|
||||
} else {
|
||||
state.socket_start().await;
|
||||
}
|
||||
}
|
||||
ApplicationEvent::SocketMessage(socket_message) => {
|
||||
if let Err(e) = state.to_gui.send(GuiUpdate::SocketConnected).await {
|
||||
error!("Could not send to gui thread! Closing coordinator: {e}");
|
||||
state.close().await;
|
||||
break;
|
||||
}
|
||||
|
||||
state.socket_send(socket_message).await;
|
||||
}
|
||||
ApplicationEvent::EnableAutomatic(do_enable) => {
|
||||
|
@ -365,16 +141,17 @@ pub async fn start_coordinator(
|
|||
.set_state(State::Null)
|
||||
.expect("Could not set pipeline state to playing");
|
||||
|
||||
state.close().await;
|
||||
|
||||
info!("Stopping Coordinator");
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn socket_listen(
|
||||
mec: Sender<ApplicationEvent>,
|
||||
socket_recv_is_alive: Arc<AtomicBool>,
|
||||
stay_alive_sck_recvr: Arc<AtomicBool>,
|
||||
mut reader: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
|
||||
) {
|
||||
if socket_recv_is_alive.load(std::sync::atomic::Ordering::SeqCst) {
|
||||
if stay_alive_sck_recvr.load(std::sync::atomic::Ordering::SeqCst) {
|
||||
while let Some(msg) = reader.next().await {
|
||||
match msg {
|
||||
Ok(val) => {
|
||||
|
@ -389,7 +166,15 @@ async fn socket_listen(
|
|||
}
|
||||
}
|
||||
|
||||
socket_recv_is_alive.store(false, Ordering::SeqCst);
|
||||
// setting this will call the internal state.socket_close next check states
|
||||
stay_alive_sck_recvr.store(false, Ordering::SeqCst);
|
||||
}
|
||||
info!("Closed socket reading thread");
|
||||
|
||||
// If the mec is closed or full, then this socket should be closing anyways
|
||||
// as there was most likely an unrecoverable error
|
||||
let _ = mec
|
||||
.send(ApplicationEvent::SocketMessage(Message::Close(None)))
|
||||
.await;
|
||||
|
||||
debug!("Closed socket reading thread");
|
||||
}
|
||||
|
|
|
@ -25,14 +25,17 @@ fn main() -> glib::ExitCode {
|
|||
{
|
||||
let file_appender = tracing_appender::rolling::daily(".", "joystick-log");
|
||||
let (non_blocking, _gaurd) = tracing_appender::non_blocking(file_appender);
|
||||
tracing_subscriber::fmt().with_writer(non_blocking).init();
|
||||
tracing_subscriber::fmt()
|
||||
.with_writer(non_blocking)
|
||||
.with_max_level(tracing::Level::DEBUG)
|
||||
.init();
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
tracing_subscriber::fmt()
|
||||
// .compact()
|
||||
.pretty()
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
.with_max_level(tracing::Level::DEBUG)
|
||||
.init();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use std::{
|
||||
net::SocketAddr,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex,
|
||||
},
|
||||
sync::{atomic::Ordering, Arc, Mutex},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
|
@ -24,7 +21,7 @@ use tracing::instrument;
|
|||
mod remote_source;
|
||||
|
||||
use crate::{
|
||||
coordinator::{ApplicationEvent, ConnectionType},
|
||||
coordinator::{ApplicationEvent, ConnectionType, SocketState},
|
||||
ui::NormalizedBoxCoords,
|
||||
};
|
||||
|
||||
|
@ -43,14 +40,19 @@ pub struct TrackerState {
|
|||
pub async fn start_socketserver(
|
||||
rt: Handle,
|
||||
mec: Sender<ApplicationEvent>,
|
||||
stay_alive: Arc<AtomicBool>,
|
||||
connection_state: Arc<SocketState>,
|
||||
tracker_state: Arc<Mutex<TrackerState>>,
|
||||
) {
|
||||
let addr = "127.0.0.1:9002";
|
||||
let listener = TcpListener::bind(&addr).await.expect("Can't listen");
|
||||
info!("Listening on: {}", addr);
|
||||
|
||||
connection_state.is_connected.store(true, Ordering::SeqCst);
|
||||
|
||||
while let Ok((stream, _)) = listener.accept().await {
|
||||
if !connection_state.stay_connected.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
let peer = stream
|
||||
.peer_addr()
|
||||
.expect("connected streams should have a peer address");
|
||||
|
@ -64,7 +66,7 @@ pub async fn start_socketserver(
|
|||
));
|
||||
}
|
||||
|
||||
stay_alive.store(false, Ordering::SeqCst);
|
||||
connection_state.is_connected.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use async_channel::Sender;
|
||||
use gtk::{
|
||||
glib::{self, object::CastNone}, prelude::{
|
||||
BoxExt, ButtonExt, Cast, GObjectPropertyExpressionExt, ListItemExt,
|
||||
ToggleButtonExt,
|
||||
}, Box, Button, Expander, Label, ListItem, ListView, ScrolledWindow, SignalListItemFactory, SingleSelection, StringList, StringObject, ToggleButton, Widget
|
||||
glib::{self, object::CastNone},
|
||||
prelude::{
|
||||
BoxExt, ButtonExt, Cast, GObjectPropertyExpressionExt, ListItemExt, ToggleButtonExt,
|
||||
},
|
||||
Box, Button, Expander, Label, ListItem, ListView, ScrolledWindow, SignalListItemFactory,
|
||||
SingleSelection, StringList, StringObject, ToggleButton, Widget,
|
||||
};
|
||||
use tracing::{error, span, Level, event};
|
||||
use tracing::{error, event, span, Level};
|
||||
|
||||
#[cfg(feature = "tracker-state-debug")]
|
||||
use tracing::debug;
|
||||
|
@ -28,7 +29,7 @@ pub struct ControlPanel {
|
|||
#[derive(Debug)]
|
||||
pub struct ExpanderMenu {
|
||||
pub top_level: Expander,
|
||||
|
||||
|
||||
pub camera_connection: Button,
|
||||
pub tracker_enable_toggle: ToggleButton,
|
||||
}
|
||||
|
@ -121,20 +122,22 @@ impl ControlPanel {
|
|||
}
|
||||
|
||||
pub fn connect_button_callbacks(&self, to_mec: Sender<ApplicationEvent>) {
|
||||
self.connection_buttons.tracker_enable_toggle.connect_clicked(glib::clone!(@strong to_mec => move |button| {
|
||||
let span = span!(Level::TRACE, "tracker_enable_toggle callback");
|
||||
let _enter = span.enter();
|
||||
if let Err(e) =
|
||||
to_mec.send_blocking(ApplicationEvent::EnableAutomatic(button.is_active()))
|
||||
{
|
||||
event!(Level::ERROR, error = ?e, "Could not send message to the MEC");
|
||||
}
|
||||
}));
|
||||
self.connection_buttons
|
||||
.tracker_enable_toggle
|
||||
.connect_clicked(glib::clone!(@strong to_mec => move |button| {
|
||||
let span = span!(Level::TRACE, "tracker_enable_toggle callback");
|
||||
let _enter = span.enter();
|
||||
if let Err(e) =
|
||||
to_mec.send_blocking(ApplicationEvent::EnableAutomatic(button.is_active()))
|
||||
{
|
||||
event!(Level::ERROR, error = ?e, "Could not send message to the MEC");
|
||||
}
|
||||
}));
|
||||
|
||||
self.connection_buttons.camera_connection.connect_clicked(glib::clone!(@strong to_mec => move |_button| {
|
||||
let span = span!(Level::TRACE, "camera_connection callback");
|
||||
let _enter = span.enter();
|
||||
match to_mec.try_send(ApplicationEvent::StartCameraSocket) {
|
||||
match to_mec.try_send(ApplicationEvent::CameraConnectionPress) {
|
||||
Ok(_) => {},
|
||||
Err(async_channel::TrySendError::Closed(_)) => panic!("Coordinator MEC is closed. Unrecoverable error."),
|
||||
Err(e) => event!(Level::ERROR, error = ?e, message = "There was an error sending to the MEC"),
|
||||
|
@ -158,7 +161,7 @@ impl ExpanderMenu {
|
|||
.expanded(true)
|
||||
.label("Connections")
|
||||
.build();
|
||||
|
||||
|
||||
let camera_connection = Button::builder()
|
||||
.label("Connect to Camera")
|
||||
.margin_top(12)
|
||||
|
@ -171,7 +174,7 @@ impl ExpanderMenu {
|
|||
|
||||
content_box.append(&camera_connection);
|
||||
content_box.append(&tracker_enable_toggle);
|
||||
|
||||
|
||||
ExpanderMenu {
|
||||
top_level: expander,
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::time::Instant;
|
|||
use gtk::cairo::Context;
|
||||
use gtk::gdk::Paintable;
|
||||
use gtk::glib::clone;
|
||||
use gtk::{gio, glib, prelude::*, AspectFrame, CssProvider, Label, ListBox};
|
||||
use gtk::{gio, glib, prelude::*, AspectFrame, CssProvider, Label};
|
||||
use gtk::{Application, ApplicationWindow};
|
||||
use log::{error, info};
|
||||
use tokio::runtime::Handle;
|
||||
|
@ -15,8 +15,8 @@ use crate::config::AppConfig;
|
|||
use crate::coordinator::{start_coordinator, ApplicationEvent, MoveEvent};
|
||||
use crate::remote_sources::TrackerState;
|
||||
|
||||
mod settings_modal;
|
||||
mod control_panel;
|
||||
mod settings_modal;
|
||||
|
||||
use control_panel::ControlPanel;
|
||||
|
||||
|
@ -110,7 +110,16 @@ pub fn on_activate(app: &Application) {
|
|||
|
||||
pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Handle) {
|
||||
let main_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);
|
||||
let left_box = ListBox::builder().width_request(200).build();
|
||||
let left_box = gtk::Box::builder()
|
||||
.width_request(300)
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.build();
|
||||
|
||||
let right_box = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.hexpand(true)
|
||||
.valign(gtk::Align::Center)
|
||||
.build();
|
||||
|
||||
// Create a window
|
||||
let window = ApplicationWindow::builder()
|
||||
|
@ -172,9 +181,8 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
|||
.css_classes(vec!["JoystickCurrent"])
|
||||
.build();
|
||||
|
||||
left_box.append(&conn_status_label);
|
||||
// left_box.append(&conn_status_label);
|
||||
left_box.append(control_panel.get_top_level());
|
||||
left_box.append(&axis_label);
|
||||
|
||||
main_box.append(&left_box);
|
||||
|
||||
|
@ -186,7 +194,12 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
|||
.obey_child(false)
|
||||
.child(&overlay_box)
|
||||
.build();
|
||||
main_box.append(&aspect);
|
||||
|
||||
right_box.append(&aspect);
|
||||
right_box.append(&conn_status_label);
|
||||
right_box.append(&axis_label);
|
||||
|
||||
main_box.append(&right_box);
|
||||
|
||||
let drawable = gtk::DrawingArea::builder().build();
|
||||
|
||||
|
@ -204,8 +217,8 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
|||
glib::timeout_add_seconds_local(
|
||||
1,
|
||||
glib::clone!(@strong items, @strong id_label => move || {
|
||||
#[cfg(feature = "tracker-state-debug")]
|
||||
debug!("Getting lock on tracker state for checking identity boxes");
|
||||
#[cfg(feature = "tracker-state-debug")]
|
||||
debug!("Getting lock on tracker state for checking identity boxes");
|
||||
|
||||
// don't update the stringlist until after letting go of the tracker state
|
||||
// due to async interweaving causing a mutex deadlock
|
||||
|
@ -233,7 +246,7 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
|||
glib::ControlFlow::Continue
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
glib::spawn_future_local(
|
||||
glib::clone!(@weak axis_label, @weak conn_status_label, @weak drawable => async move {
|
||||
while let Ok(d) = gui_recv.recv().await {
|
||||
|
@ -253,15 +266,15 @@ pub fn build_ui(app: &Application, config: Arc<RwLock<AppConfig>>, runtime: Hand
|
|||
|
||||
},
|
||||
GuiUpdate::SocketConnecting => {
|
||||
control_panel.connection_buttons.camera_connection.set_sensitive(true);
|
||||
control_panel.connection_buttons.camera_connection.set_label("Press to Cancel");
|
||||
conn_status_label.set_label("Connected");
|
||||
control_panel.connection_buttons.camera_connection.set_sensitive(false);
|
||||
control_panel.connection_buttons.camera_connection.set_label("Please wait");
|
||||
conn_status_label.set_label("Connecting");
|
||||
|
||||
conn_status_label.set_css_classes(&["LoadingConnection"]);
|
||||
|
||||
},
|
||||
GuiUpdate::SocketDisconnected => {
|
||||
control_panel.connection_buttons.camera_connection.set_sensitive(false);
|
||||
control_panel.connection_buttons.camera_connection.set_sensitive(true);
|
||||
control_panel.connection_buttons.camera_connection.set_label("Press to Connect to Camera");
|
||||
conn_status_label.set_label("Not Connected to Camera");
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ impl ConnectionsModal {
|
|||
}
|
||||
// FBI!!! OPEN UP!!!!
|
||||
}
|
||||
|
||||
|
||||
window.close();
|
||||
|
||||
info!("Please nicholas, add a non-crashing parse");
|
||||
|
|
Loading…
Reference in a new issue