v2.0.1 - Pirate Stache - Unix Sockets

Added basic setup for Unix sockets.

Need to add shell REPL so a host can talk to the server. It currently
only connects and echoes back commands.
This commit is contained in:
saw 2021-07-14 22:46:06 -04:00
parent 2404b04e76
commit b093903fbf

View File

@ -70,6 +70,42 @@ async fn debug(
HttpResponse::Ok().body(serde_json::to_string_pretty(data.as_ref()).unwrap())
}
async fn socket_loop(socket: &UnixStream) -> Result<(), Box<dyn Error>> {
loop {
let mut data = vec![0; 1024];
socket.readable().await?;
let mut command = String::new();
loop {
match socket.try_read(&mut data) {
Ok(0) => break,
Ok(_n) => {
command.push_str(&String::from_utf8(data.clone()).unwrap().trim());
println!("command: {}", command);
},
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
break;
},
Err(e) => {
return Err(e.into());
}
}
}
socket.writable().await?;
match socket.try_write(&command.into_bytes()) {
Ok(_n) => {
},
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
continue;
},
Err(e) => {
return Err(e.into());
}
}
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
/* quick and dirty logging */
@ -152,6 +188,78 @@ async fn main() -> std::io::Result<()> {
let wb = web_data.clone();
println!("{}", style("Loaded/Created application data files!").green());
println!("Connecting to Unix socket...");
let (tx0, rx0) = oneshot::channel::<bool>();
/* NOTE: More phases will probably exist in the future */
enum AppPhase {
Normal,
Shutdown
}
let (s_tx, mut s_rx) = watch::channel::<AppPhase>(AppPhase::Normal);
let rt = Runtime::new().unwrap();
let _guard = rt.enter();
/* spawn the thread that manages the unix socket */
tokio::spawn(async move {
let p = Path::new("./boarders.sock");
if p.exists() {
std::fs::remove_file(p).unwrap();
}
let socket = UnixListener::bind("./boarders.sock").unwrap_or_else(|_| {
panic!("{}", style("Could not connect to Unix socket").red());
});
println!("{}", style("Listening on Unix socket!").green());
if tx0.send(true).is_err() {
panic!("{}", style("[FATAL] Thread reciever was dropped! (should never happen)").red().bold());
}
/*
* HACK: clone the reciever a bunch of times to get around moves
* not sure if there's a better way
*/
let s_rx_0 = s_rx.clone();
let spawn_t = tokio::spawn(async move {
let s_rx = s_rx_0.clone();
loop {
let mut s_rx = s_rx.clone();
/* accept socket then wait for exit, or shutdown signal */
let (conn, _addr) = socket.accept().await.unwrap();
tokio::spawn(async move {
select! {
_socket = socket_loop(&conn) => 0,
_state = s_rx.changed() => 1
}
});
}
});
/*
* FIXME: use enums when I feel like it (not urgent)
*/
match select! {
_st = spawn_t => 0,
state = s_rx.changed() => if state.is_ok() {
match *s_rx.borrow() {
AppPhase::Shutdown => 1,
_ => 0
}
} else {
0
}
} {
0 => println!("Client disconnected"),
1 => println!("Shut down client thread(s)"),
_ => println!("Unexpected value from client thread")
}
});
/* why do I want a special message for that? Honestly I don't know... */
rx0.await.unwrap_or_else(
|_| panic!("{}", style("[FATAL] Thread transmitter was dropped! (should never happen)").red().bold())
);
println!("{}", style("Finished initialization").green().bold());
println!("Starting server...");