diff --git a/Cargo.toml b/Cargo.toml index 30c7d10..d17ed8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clap = "2.33.0" +tokio = { version= "1", features = ["full"] } +tokio-stream = "0.1.6" +warp = "0.3" +serde = "*" +serde_derive = "*" +toml = "0.5" +serde_json = "1.0" +futures = { version = "0.3", default-features=false} +uuid = { version = "0.4", features = ["serde", "v4"] } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e7a11a9..b2bbc01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,41 @@ -fn main() { - println!("Hello, world!"); +mod mods; +use std::{collections::HashMap, convert::Infallible, sync::Arc, fs, fs::File, io::prelude::*, env}; +use tokio::sync::{mpsc, Mutex}; +use warp::{ws::Message, Filter, Rejection}; +use toml; +use serde_derive::Deserialize; + +#[derive(Deserialize)] +struct General { + websocket_ip: String, + websocket_port: String, + restore_conf: String, +} + + +#[derive(Debug, Clone)] +pub struct Client { + pub client_id: String, + pub sender: Option>>, +} + +type Clients = Arc>>; +type Result = std::result::Result; + +#[tokio::main] +async fn main() { + let clients: Clients = Arc::new(Mutex::new(HashMap::new())); + println!("Configuring websocket route"); + let ws_route = warp::path("ws") + .and(warp::ws()) + .and(with_clients(clients.clone())) + .and_then(mods::handlers::ws_handler); + + let routes = ws_route.with(warp::cors().allow_any_origin()); + println!("Starting server"); + warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; +} + +fn with_clients(clients: Clients) -> impl Filter + Clone { + warp::any().map(move || clients.clone()) } diff --git a/src/mods.rs b/src/mods.rs new file mode 100644 index 0000000..3a3bd76 --- /dev/null +++ b/src/mods.rs @@ -0,0 +1,2 @@ +pub mod handlers; +pub mod ws; \ No newline at end of file diff --git a/src/mods/handlers.rs b/src/mods/handlers.rs new file mode 100644 index 0000000..e5dc190 --- /dev/null +++ b/src/mods/handlers.rs @@ -0,0 +1,8 @@ +use crate::{mods::ws, Clients, Result}; +use warp::Reply; + +pub async fn ws_handler(ws: warp::ws::Ws, clients: Clients) -> Result { + println!("ws_handler"); + + Ok(ws.on_upgrade(move |socket| ws::client_connection(socket, clients))) +} \ No newline at end of file diff --git a/src/mods/ws.rs b/src/mods/ws.rs new file mode 100644 index 0000000..885a283 --- /dev/null +++ b/src/mods/ws.rs @@ -0,0 +1,65 @@ +use crate::{Client, Clients}; +use futures::{FutureExt, StreamExt}; +use tokio::sync::mpsc; +use tokio_stream::wrappers::UnboundedReceiverStream; +use uuid::Uuid; +use warp::ws::{Message, WebSocket}; + +use toml; + + +pub async fn client_connection(ws: WebSocket, clients: Clients) { + println!("establishing client connection... {:?}", ws); + + let (client_ws_sender, mut client_ws_rcv) = ws.split(); + let (client_sender, client_rcv) = mpsc::unbounded_channel(); + + let client_rcv = UnboundedReceiverStream::new(client_rcv); + + tokio::task::spawn(client_rcv.forward(client_ws_sender).map(|result| { + if let Err(e) = result { + println!("error sending websocket msg: {}", e); + } + })); + + let uuid = Uuid::new_v4().simple().to_string(); + + let new_client = Client { + client_id: uuid.clone(), + sender: Some(client_sender), + }; + + clients.lock().await.insert(uuid.clone(), new_client); + while let Some(result) = client_ws_rcv.next().await { + let msg = match result { + Ok(msg) => msg, + Err(e) => { + println!("error receiving message for id {}): {}", uuid.clone(), e); + break; + } + }; + client_msg(&uuid, msg, &clients).await; + } + clients.lock().await.remove(&uuid); + println!("{} disconnected", uuid); +} + +async fn client_msg(client_id: &str, msg: Message, clients: &Clients) { + println!("received message from {}: {:?}", client_id, msg); + + let message = match msg.to_str() { + Ok(v) => v, + Err(_) => return, + }; + let locked = clients.lock().await; + match locked.get(client_id) { + Some(v) => { + if let Some(sender) = &v.sender { + println!("sending pong"); + let _ = sender.send(Ok(Message::text(message))); + } + } + None => return, + } + return; +} \ No newline at end of file