feat: simple ws server impl

This commit is contained in:
əlemi 2024-11-10 02:00:51 +01:00
parent 13a619866d
commit 3770939b9f
Signed by: alemi
GPG key ID: A4895B84D311642C
2 changed files with 75 additions and 0 deletions

View file

@ -10,9 +10,20 @@ name = "mmp-port"
path = "src/port/main.rs"
required-features = ["port"]
[[bin]]
name = "mmp-server"
path = "src/server/main.rs"
required-features = ["server"]
[dependencies]
midi-msg = { version = "0.7", optional = true }
midir = { version = "0.10", optional = true }
tokio = { version = "1.41", features = ["net", "rt", "macros", "sync"], optional = true }
tokio-tungstenite = { version = "0.24", optional = true }
futures-util = { version = "0.3", optional = true }
serde_json = { version = "1.0", optional = true }
[features]
default = []
port = ["dep:midi-msg", "dep:midir"]
server = ["dep:tokio", "dep:tokio-tungstenite", "dep:futures-util", "dep:serde_json"]

64
src/server/main.rs Normal file
View file

@ -0,0 +1,64 @@
use std::{env, io::Error};
use futures_util::TryStreamExt;
use tokio::{io::AsyncWriteExt, net::{TcpListener, TcpStream}, sync::mpsc};
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Error> {
let addr = env::args().nth(1).unwrap_or_else(|| "127.0.0.1:64080".to_string());
let addr2 = env::args().nth(2).unwrap_or_else(|| "0.0.0.0:60080".to_string());
let listener = TcpListener::bind(&addr).await.unwrap();
println!("Listening on: {}", addr);
let (tx, mut rx) = mpsc::unbounded_channel::<[u8;2]>();
tokio::spawn(async move {
let control_socket = TcpListener::bind(&addr2).await.unwrap();
while let Ok((mut stream, addr)) = control_socket.accept().await {
// don't spawn a new task: we only serve controls to one user at a time
println!("user {addr} connected, sending control signals...");
while let Some([ctrl, val]) = rx.recv().await {
if let Err(e) = stream.write_all(&[ctrl, val]).await {
eprintln!("error sending control, disconnecting -- {e}");
break;
}
}
}
});
while let Ok((stream, _)) = listener.accept().await {
tokio::spawn(accept_connection(stream, tx.clone()));
}
Ok(())
}
async fn accept_connection(stream: TcpStream, tx: mpsc::UnboundedSender<[u8;2]>) {
let addr = stream.peer_addr().expect("connected streams should have a peer address");
println!("Peer address: {}", addr);
let mut ws_stream = tokio_tungstenite::accept_async(stream)
.await
.expect("Error during the websocket handshake occurred");
println!("New WebSocket connection: {}", addr);
loop {
match ws_stream.try_next().await {
Err(e) => break eprintln!("user {addr} disconnected with error: {e}"),
Ok(None) => break println!("user {addr} disconnected"),
Ok(Some(msg)) => match msg {
tokio_tungstenite::tungstenite::Message::Text(txt) => {
let Ok([cmd, val]) = serde_json::from_str::<[u8;2]>(&txt) else {
break eprintln!("invalid websocket command: {txt}");
};
if let Err(e) = tx.send([cmd, val]) {
eprintln!("control channel is dead!");
}
},
m => eprintln!("unexpected message: {m:?}"),
},
}
}
}