Compare commits
2 commits
1995aaa858
...
9e1e08851e
Author | SHA1 | Date | |
---|---|---|---|
|
9e1e08851e | ||
|
c32b0d289e |
4 changed files with 70 additions and 23 deletions
|
@ -25,8 +25,6 @@ impl JoecalState {
|
||||||
|
|
||||||
pub async fn listen_multicast(&self, config: &Config) -> crate::error::Result<()> {
|
pub async fn listen_multicast(&self, config: &Config) -> crate::error::Result<()> {
|
||||||
let mut buf = [0; 65536];
|
let mut buf = [0; 65536];
|
||||||
println!("Socket local addr: {:?}", self.socket.local_addr()?);
|
|
||||||
println!("Listening on multicast addr: {}", config.multicast_addr);
|
|
||||||
|
|
||||||
let mut timeout = tokio::time::interval(Duration::from_secs(5));
|
let mut timeout = tokio::time::interval(Duration::from_secs(5));
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,9 @@ impl JoecalState {
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> crate::error::Result<()> {
|
) -> crate::error::Result<()> {
|
||||||
let app = self.create_router(config);
|
let app = self.create_router(config);
|
||||||
|
// TODO: make addr config
|
||||||
let addr = SocketAddr::from(([0, 0, 0, 0], config.port));
|
let addr = SocketAddr::from(([0, 0, 0, 0], config.port));
|
||||||
|
|
||||||
let listener = TcpListener::bind(&addr).await?;
|
let listener = TcpListener::bind(&addr).await?;
|
||||||
println!("HTTP server listening on {addr}");
|
|
||||||
|
|
||||||
axum::serve(
|
axum::serve(
|
||||||
listener,
|
listener,
|
||||||
|
|
19
src/main.rs
19
src/main.rs
|
@ -1,3 +1,4 @@
|
||||||
|
#![feature(slice_as_array)]
|
||||||
use std::{collections::BTreeMap, io, net::SocketAddr};
|
use std::{collections::BTreeMap, io, net::SocketAddr};
|
||||||
|
|
||||||
use joecalsend::{Config, JoecalState, RunningState, error, models::Device};
|
use joecalsend::{Config, JoecalState, RunningState, error, models::Device};
|
||||||
|
@ -57,11 +58,13 @@ async fn main() -> error::Result<()> {
|
||||||
Ok(result?)
|
Ok(result?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Peers = BTreeMap<SocketAddr, (String, String)>;
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
state: JoecalState,
|
state: JoecalState,
|
||||||
screen: CurrentScreen,
|
screen: CurrentScreen,
|
||||||
// addr -> (alias, fingerprint)
|
// addr -> (alias, fingerprint)
|
||||||
peers: BTreeMap<SocketAddr, (String, String)>,
|
peers: Peers,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -69,6 +72,7 @@ enum CurrentScreen {
|
||||||
Main,
|
Main,
|
||||||
Sending,
|
Sending,
|
||||||
Receiving,
|
Receiving,
|
||||||
|
Stopping,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
@ -84,11 +88,13 @@ impl App {
|
||||||
loop {
|
loop {
|
||||||
terminal.draw(|frame| self.draw(frame))?;
|
terminal.draw(|frame| self.draw(frame))?;
|
||||||
self.handle_events().await?;
|
self.handle_events().await?;
|
||||||
let rstate = self.state.running_state.lock().await;
|
|
||||||
if *rstate == RunningState::Stopping {
|
if self.screen == CurrentScreen::Stopping {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let peers = self.state.peers.lock().await;
|
let peers = self.state.peers.lock().await;
|
||||||
|
self.peers.clear();
|
||||||
peers.iter().for_each(|(k, v)| {
|
peers.iter().for_each(|(k, v)| {
|
||||||
// k is fingerprint, v is addr, device
|
// k is fingerprint, v is addr, device
|
||||||
let addr = v.0;
|
let addr = v.0;
|
||||||
|
@ -100,10 +106,6 @@ impl App {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, frame: &mut Frame) {
|
|
||||||
frame.render_widget(self, frame.area());
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_events(&mut self) -> io::Result<()> {
|
async fn handle_events(&mut self) -> io::Result<()> {
|
||||||
match event::read()? {
|
match event::read()? {
|
||||||
// it's important to check that the event is a key press event as
|
// it's important to check that the event is a key press event as
|
||||||
|
@ -126,8 +128,9 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn exit(&self) {
|
async fn exit(&mut self) {
|
||||||
self.state.stop().await;
|
self.state.stop().await;
|
||||||
|
self.screen = CurrentScreen::Stopping;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send(&mut self) {
|
async fn send(&mut self) {
|
||||||
|
|
69
src/ui.rs
69
src/ui.rs
|
@ -5,7 +5,7 @@ use ratatui::{
|
||||||
layout::{Constraint, Direction, Layout, Rect},
|
layout::{Constraint, Direction, Layout, Rect},
|
||||||
style::Stylize,
|
style::Stylize,
|
||||||
text::{Line, Span},
|
text::{Line, Span},
|
||||||
widgets::{List, ListItem},
|
widgets::{Block, Borders, List, ListItem},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::App;
|
use crate::App;
|
||||||
|
@ -35,16 +35,63 @@ fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn peers(&self, frame: &mut Frame) {
|
pub fn draw(&self, frame: &mut Frame) {
|
||||||
let mut items = Vec::with_capacity(self.peers.len());
|
let [top, middle, bottom] = Layout::default()
|
||||||
for (k, v) in self.peers.iter() {
|
.direction(Direction::Vertical)
|
||||||
let item = format!("{:?}: {}({})", k, v.0, v.1);
|
.constraints([Constraint::Min(3), Constraint::Min(3), Constraint::Min(3)])
|
||||||
let s = Line::from(item.yellow());
|
.split(frame.area())
|
||||||
|
.as_array()
|
||||||
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let item = ListItem::new(s);
|
let [footer_left, footer_right] = Layout::default()
|
||||||
items.push(item);
|
.direction(Direction::Horizontal)
|
||||||
}
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||||
let list = List::new(items);
|
.split(bottom)
|
||||||
frame.render_widget(list, frame.area());
|
.as_array()
|
||||||
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
frame.render_widget(self, frame.area());
|
||||||
|
network_info(frame, footer_left);
|
||||||
|
peers(&self.peers, frame, footer_right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn peers(peers: &crate::Peers, frame: &mut Frame, area: Rect) {
|
||||||
|
let mut items = Vec::with_capacity(peers.len());
|
||||||
|
for (k, v) in peers.iter() {
|
||||||
|
let item = format!("{:?}: {} ({})", k, v.0, v.1);
|
||||||
|
let s = Line::from(item.yellow());
|
||||||
|
|
||||||
|
let item = ListItem::new(s);
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
let block = Block::default().title("Peers").borders(Borders::all());
|
||||||
|
let list = List::new(items).block(block);
|
||||||
|
frame.render_widget(list, area);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn network_info(frame: &mut Frame, area: Rect) {
|
||||||
|
let udp: Line = format!("UDP socket: {:?}", joecalsend::LISTENING_SOCKET_ADDR)
|
||||||
|
.yellow()
|
||||||
|
.into();
|
||||||
|
let multicast: Line = format!(
|
||||||
|
"Multicast address: {:?}:{}",
|
||||||
|
joecalsend::MULTICAST_IP,
|
||||||
|
joecalsend::DEFAULT_PORT
|
||||||
|
)
|
||||||
|
.yellow()
|
||||||
|
.into();
|
||||||
|
let http: Line = format!("HTTP address: {:?}", joecalsend::LISTENING_SOCKET_ADDR)
|
||||||
|
.yellow()
|
||||||
|
.into();
|
||||||
|
let items = [
|
||||||
|
ListItem::new(udp),
|
||||||
|
ListItem::new(multicast),
|
||||||
|
ListItem::new(http),
|
||||||
|
];
|
||||||
|
let block = Block::default().title("Listeners").borders(Borders::all());
|
||||||
|
let list = List::new(items).block(block);
|
||||||
|
frame.render_widget(list, area);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue