2024-06-22 23:19:04 +02:00
|
|
|
use anyhow::Result;
|
|
|
|
|
use fern::colors::{Color, ColoredLevelConfig};
|
2024-06-29 16:01:40 +02:00
|
|
|
use log::{debug, error, info, warn, Level};
|
|
|
|
|
use serde_json::{json, Value};
|
|
|
|
|
use std::{borrow::Borrow, io};
|
2024-05-05 14:42:25 +02:00
|
|
|
use tokio::{
|
|
|
|
|
self,
|
|
|
|
|
io::{AsyncBufReadExt, AsyncWriteExt, BufStream},
|
|
|
|
|
net::{TcpListener, TcpStream},
|
2024-06-29 16:01:40 +02:00
|
|
|
sync::{mpsc, watch},
|
|
|
|
|
task::JoinSet,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use axum::{
|
|
|
|
|
extract::State,
|
|
|
|
|
http::StatusCode,
|
|
|
|
|
routing::{get, post},
|
|
|
|
|
Json, Router,
|
|
|
|
|
};
|
|
|
|
|
use tower_http::{
|
|
|
|
|
services::{ServeDir, ServeFile},
|
|
|
|
|
trace::TraceLayer,
|
2024-05-05 14:42:25 +02:00
|
|
|
};
|
|
|
|
|
|
2024-10-03 22:54:05 +02:00
|
|
|
use radomctld::{
|
|
|
|
|
logger::setup_logger,
|
|
|
|
|
rotctlprotocol::{parse_command, Command},
|
|
|
|
|
rotor::control_rotor,
|
|
|
|
|
};
|
2024-05-05 15:07:08 +02:00
|
|
|
|
2024-05-05 17:38:28 +02:00
|
|
|
async fn process_socket(
|
|
|
|
|
socket: TcpStream,
|
|
|
|
|
cmd_tx: mpsc::Sender<Command>,
|
|
|
|
|
mut pos_rx: watch::Receiver<(f32, f32)>,
|
|
|
|
|
) {
|
2024-05-05 14:42:25 +02:00
|
|
|
let mut stream = BufStream::new(socket);
|
|
|
|
|
|
|
|
|
|
let mut line = String::new();
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
if let Ok(n) = stream.read_line(&mut line).await {
|
|
|
|
|
if n == 0 {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-22 23:19:04 +02:00
|
|
|
debug!("Received: {}", line.strip_suffix("\n").unwrap());
|
2024-05-05 14:42:25 +02:00
|
|
|
|
2024-06-29 13:51:29 +02:00
|
|
|
match parse_command(&line) {
|
2024-05-05 15:07:08 +02:00
|
|
|
Ok(cmd) => match cmd {
|
|
|
|
|
Command::GetPos => {
|
2024-05-05 17:38:28 +02:00
|
|
|
let (az, el) = pos_rx.borrow().clone();
|
|
|
|
|
|
2024-05-05 15:07:08 +02:00
|
|
|
stream
|
|
|
|
|
.write_all(format!("{}\n{}\n", az, el).as_bytes())
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
stream.flush().await.unwrap();
|
|
|
|
|
}
|
2024-05-05 17:38:28 +02:00
|
|
|
Command::Exit => {
|
2024-05-05 15:07:08 +02:00
|
|
|
stream.write_all("RPRT 0\n".as_bytes()).await.unwrap();
|
|
|
|
|
stream.flush().await.unwrap();
|
2024-05-05 17:38:28 +02:00
|
|
|
return;
|
2024-05-05 15:07:08 +02:00
|
|
|
}
|
2024-05-05 17:38:28 +02:00
|
|
|
cmd => {
|
|
|
|
|
cmd_tx.send(cmd).await.unwrap();
|
2024-05-05 15:07:08 +02:00
|
|
|
stream.write_all("RPRT 0\n".as_bytes()).await.unwrap();
|
|
|
|
|
stream.flush().await.unwrap();
|
|
|
|
|
}
|
|
|
|
|
},
|
2024-05-05 14:42:25 +02:00
|
|
|
Err(msg) => {
|
2024-06-22 23:19:04 +02:00
|
|
|
error!("Unable to parse input:\n{}", msg);
|
|
|
|
|
stream.write_all("RPRT 6\n".as_bytes()).await.unwrap();
|
2024-05-05 14:42:25 +02:00
|
|
|
stream.flush().await.unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line.clear();
|
|
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-29 16:01:40 +02:00
|
|
|
#[derive(Clone)]
|
|
|
|
|
struct AxumAppState {
|
|
|
|
|
pos_rx: watch::Receiver<(f32, f32)>,
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-05 14:42:25 +02:00
|
|
|
#[tokio::main]
|
2024-06-22 23:19:04 +02:00
|
|
|
async fn main() -> Result<()> {
|
|
|
|
|
setup_logger()?;
|
|
|
|
|
|
2024-05-05 17:38:28 +02:00
|
|
|
let (cmd_tx, cmd_rx) = mpsc::channel::<Command>(16);
|
|
|
|
|
let (pos_tx, pos_rx) = watch::channel::<(f32, f32)>((0.0, 0.0));
|
|
|
|
|
|
2024-06-29 16:01:40 +02:00
|
|
|
let mut tasks = JoinSet::new();
|
|
|
|
|
|
|
|
|
|
tasks.spawn(async move { control_rotor(cmd_rx, pos_tx).await });
|
|
|
|
|
|
|
|
|
|
let state = AxumAppState {
|
|
|
|
|
pos_rx: pos_rx.clone(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tasks.spawn(async move {
|
|
|
|
|
let app = Router::new()
|
|
|
|
|
.route_service("/", ServeFile::new("assets/index.html"))
|
|
|
|
|
.route("/state", get(get_state))
|
|
|
|
|
.with_state(state)
|
|
|
|
|
.layer(TraceLayer::new_for_http());
|
|
|
|
|
|
|
|
|
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await?;
|
|
|
|
|
axum::serve(listener, app).await?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
2024-05-05 17:38:28 +02:00
|
|
|
});
|
|
|
|
|
|
2024-06-29 16:01:40 +02:00
|
|
|
tasks.spawn(async move {
|
|
|
|
|
let listener = TcpListener::bind("127.0.0.1:1337").await?;
|
2024-05-05 14:42:25 +02:00
|
|
|
|
2024-06-29 16:01:40 +02:00
|
|
|
loop {
|
|
|
|
|
let (socket, _) = listener.accept().await?;
|
|
|
|
|
|
|
|
|
|
let cmd_tx = cmd_tx.clone();
|
|
|
|
|
let pos_rx = pos_rx.clone();
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
process_socket(socket, cmd_tx, pos_rx).await;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-05-05 17:38:28 +02:00
|
|
|
|
2024-06-29 16:01:40 +02:00
|
|
|
while let Some(res) = tasks.join_next().await {
|
|
|
|
|
res.unwrap();
|
2024-05-05 14:42:25 +02:00
|
|
|
}
|
2024-06-29 16:01:40 +02:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn get_state(State(state): State<AxumAppState>) -> Json<Value> {
|
|
|
|
|
let (az, el) = state.pos_rx.borrow().clone();
|
|
|
|
|
|
|
|
|
|
Json(json!({
|
|
|
|
|
"position" : {
|
|
|
|
|
"az": az,
|
|
|
|
|
"el": el
|
|
|
|
|
}
|
|
|
|
|
}))
|
2024-05-03 16:16:24 +02:00
|
|
|
}
|