feat: add initial server + routes

This commit is contained in:
itsscb 2025-05-23 21:54:01 +02:00
parent 908d6bd67b
commit d61e6da1d2
6 changed files with 115 additions and 119 deletions

View File

@ -14,6 +14,7 @@ serde_json = "1.0.140"
sqlx = { version = "0.8.5", features = ["macros", "runtime-tokio", "sqlite", "uuid"] } sqlx = { version = "0.8.5", features = ["macros", "runtime-tokio", "sqlite", "uuid"] }
tokio = { version = "1.44.2", features = ["full"] } tokio = { version = "1.44.2", features = ["full"] }
tower = "0.5.2" tower = "0.5.2"
tower-http = { version = "0.6.4", features = ["fs"] }
tracing = { version = "0.1.41", features = ["async-await"] } tracing = { version = "0.1.41", features = ["async-await"] }
tracing-subscriber = "0.3.19" tracing-subscriber = "0.3.19"
uuid = { version = "1.16.0", features = ["v4"] } uuid = { version = "1.16.0", features = ["v4"] }

View File

@ -1,2 +1,21 @@
#![allow(clippy::unwrap_used)]
use router::new_router;
use tokio::net::TcpListener;
use tracing::info;
mod db; mod db;
mod router;
mod script; mod script;
pub fn run() {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
tracing_subscriber::fmt::init();
let app = new_router();
let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
info!("listening"=?listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
});
}

View File

@ -1,16 +1,13 @@
#![allow(clippy::unwrap_used, clippy::expect_used)] #![allow(dead_code, clippy::unwrap_used, clippy::expect_used)]
use axum::{ use axum::{
Router, // Router,
extract::ws::{Message, WebSocket, WebSocketUpgrade}, extract::ws::{Message, WebSocket, WebSocketUpgrade},
response::IntoResponse, response::IntoResponse,
routing::get, // routing::get,
}; };
use futures::{SinkExt, StreamExt}; use futures::{SinkExt, StreamExt};
use std::{ use std::sync::{Arc, Mutex};
sync::{Arc, Mutex}, use tokio::task;
time::Duration,
};
use tokio::{task, time};
use tracing::info; use tracing::info;
use std::process::Stdio; use std::process::Stdio;
@ -20,87 +17,44 @@ use tokio::sync::mpsc; // Use std::process::Stdio
type Tx = tokio::sync::mpsc::UnboundedSender<Message>; type Tx = tokio::sync::mpsc::UnboundedSender<Message>;
#[tokio::main] fn main() {
async fn main() { befehlswerk::run();
tracing_subscriber::fmt().pretty().init();
let clients = Arc::new(Mutex::new(Vec::<Tx>::new()));
let clients_clone = Arc::clone(&clients);
let (tx, mut rx) = mpsc::channel(100);
task::spawn(async move {
let cmd = "$count = 0; while($count -lt 10000) {
#Write-Error 'test-error'
#write-warning 'test-warning'
Write-Output \"$(Get-Date -Format 'yyyy-MM-dd_HH:mm:ss'): Hello World #$($count) from PowerShell!\"
$count += 1
}";
spawn_and_capture(cmd, tx).await;
});
// In batches - but this does not preserve the order. Or does it? It's possible that stdout is
// faster than stderr.
task::spawn(async move {
loop {
let mut closed = vec![];
let mut messages = vec![];
if rx.recv_many(&mut messages, 2000).await > 0 {
let msg = Message::Text(
messages
.into_iter()
.map(|m| if m.1 { format!("[ERR]: {}", m.0) } else { m.0 })
.collect::<Vec<_>>()
.join("\n")
.into(),
);
{
let mut lock = clients_clone.lock().unwrap();
for (i, tx) in lock.iter().enumerate() {
if tx.send(msg.clone()).is_err() {
closed.push(i);
} }
} // #[tokio::main]
// async fn main() {
for i in closed.iter().rev() { // tracing_subscriber::fmt().pretty().init();
lock.remove(*i); // let clients = Arc::new(Mutex::new(Vec::<Tx>::new()));
} // let clients_clone = Arc::clone(&clients);
}
//for message in messages {
// let msg = Message::Text(if message.1 {
// format!("[ERR]: {}", message.0).into()
// } else {
// message.0.into()
// });
// {
// let mut lock = clients_clone.lock().unwrap();
// for (i, tx) in lock.iter().enumerate() {
// if tx.send(msg.clone()).is_err() {
// closed.push(i);
// }
// }
// //
// for i in closed.iter().rev() { // let (tx, mut rx) = mpsc::channel(100);
// lock.remove(*i); //
// } // task::spawn(async move {
// } // let cmd = "$count = 0; while($count -lt 10000) {
//} // #Write-Error 'test-error'
} // #write-warning 'test-warning'
//time::sleep(Duration::from_millis(500)).await; // Write-Output \"$(Get-Date -Format 'yyyy-MM-dd_HH:mm:ss'): Hello World #$($count) from PowerShell!\"
} // $count += 1
}); // }";
// spawn_and_capture(cmd, tx).await;
// });
//
// // In batches - but this does not preserve the order. Or does it? It's possible that stdout is
// // faster than stderr.
// task::spawn(async move { // task::spawn(async move {
// loop { // loop {
// let mut closed = vec![]; // let mut closed = vec![];
// //
// if let Some((line, is_err)) = rx.recv().await { // let mut messages = vec![];
// let msg = Message::Text(if is_err { //
// format!("[ERR]: {line}").into() // if rx.recv_many(&mut messages, 2000).await > 0 {
// } else { // let msg = Message::Text(
// line.into() // messages
// }); // .into_iter()
// .map(|m| if m.1 { format!("[ERR]: {}", m.0) } else { m.0 })
// .collect::<Vec<_>>()
// .join("\n")
// .into(),
// );
// { // {
// let mut lock = clients_clone.lock().unwrap(); // let mut lock = clients_clone.lock().unwrap();
// for (i, tx) in lock.iter().enumerate() { // for (i, tx) in lock.iter().enumerate() {
@ -113,25 +67,21 @@ async fn main() {
// lock.remove(*i); // lock.remove(*i);
// } // }
// } // }
//
// //time::sleep(Duration::from_millis(200)).await;
// } else {
// break;
// } // }
// } // }
// }); // });
//
let app = Router::new().route( // let app = Router::new().route(
"/ws", // "/ws",
get({ // get({
let clients = Arc::clone(&clients); // let clients = Arc::clone(&clients);
move |ws| handle_socket(ws, Arc::clone(&clients)) // move |ws| handle_socket(ws, Arc::clone(&clients))
}), // }),
); // );
//
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); // let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap(); // axum::serve(listener, app).await.unwrap();
} // }
async fn handle_socket(ws: WebSocketUpgrade, clients: Arc<Mutex<Vec<Tx>>>) -> impl IntoResponse { async fn handle_socket(ws: WebSocketUpgrade, clients: Arc<Mutex<Vec<Tx>>>) -> impl IntoResponse {
ws.on_upgrade(move |socket| handle_ws(socket, clients)) ws.on_upgrade(move |socket| handle_ws(socket, clients))

11
src/router.rs Normal file
View File

@ -0,0 +1,11 @@
use axum::routing::{get, get_service};
use routes::scripts::get_scripts;
use tower_http::services::ServeDir;
mod routes;
pub fn new_router() -> axum::Router {
axum::Router::new()
.fallback_service(get_service(ServeDir::new("assets")))
// .nest_service("/", ServeDir::new("assets"))
.route("/scripts", get(get_scripts))
}

1
src/router/routes.rs Normal file
View File

@ -0,0 +1 @@
pub mod scripts;

View File

@ -0,0 +1,14 @@
use axum::response::{Html, IntoResponse};
pub async fn get_scripts() -> impl IntoResponse {
Html(
r##"
<section id="scripts">
<ul>
<li>Script1</li>
<li>Script2</li>
</ul>
<button hx-get="/scripts" hx-swap="outerHTML" hx-target="#scripts">Refresh</button>
</section>"##,
)
}