diff --git a/Cargo.toml b/Cargo.toml index 3209341..9510dac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,8 @@ toml = "0.8" url = { version = "2.5", features = ["serde"] } uuid = { version = "1.16", features = ["serde", "v7"] } random-string = "1.1" +actix-ws = "0.3.0" +futures-util = "0.3.31" [dependencies.tokio] version = "1.44" diff --git a/src/main.rs b/src/main.rs index 37011ed..a80ad0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,16 @@ use actix_cors::Cors; -use actix_web::{App, HttpServer, web}; +use actix_web::{web, App, HttpServer}; use argon2::Argon2; use clap::Parser; +use futures::try_join; use simple_logger::SimpleLogger; use sqlx::{PgPool, Pool, Postgres}; +use wss::echo; use std::time::SystemTime; mod config; use config::{Config, ConfigBuilder}; mod api; +mod wss; pub mod utils; pub mod structs; @@ -169,43 +172,52 @@ async fn main() -> Result<(), Error> { argon2: Argon2::default(), start_time: SystemTime::now(), }; - - HttpServer::new(move || { - // Set CORS headers - let cors = Cors::default() - /* - Set Allowed-Control-Allow-Origin header to whatever - the request's Origin header is. Must be done like this - rather than setting it to "*" due to CORS not allowing - sending of credentials (cookies) with wildcard origin. - */ - .allowed_origin_fn(|_origin, _req_head| { - true - }) - /* - Allows any request method in CORS preflight requests. - This will be restricted to only ones actually in use later. - */ - .allow_any_method() - /* - Allows any header(s) in request in CORS preflight requests. - This wll be restricted to only ones actually in use later. - */ - .allow_any_header() - /* - Allows browser to include cookies in requests. - This is needed for receiving the secure HttpOnly refresh_token cookie. - */ - .supports_credentials(); + try_join!( + HttpServer::new(move || { + // Set CORS headers + let cors = Cors::default() + /* + Set Allowed-Control-Allow-Origin header to whatever + the request's Origin header is. Must be done like this + rather than setting it to "*" due to CORS not allowing + sending of credentials (cookies) with wildcard origin. + */ + .allowed_origin_fn(|_origin, _req_head| { + true + }) + /* + Allows any request method in CORS preflight requests. + This will be restricted to only ones actually in use later. + */ + .allow_any_method() + /* + Allows any header(s) in request in CORS preflight requests. + This wll be restricted to only ones actually in use later. + */ + .allow_any_header() + /* + Allows browser to include cookies in requests. + This is needed for receiving the secure HttpOnly refresh_token cookie. + */ + .supports_credentials(); + + App::new() + .app_data(web::Data::new(data.clone())) + .wrap(cors) + .service(api::web()) + }) + .bind((web.url, web.port))? + .run(), + + HttpServer::new(|| { + App::new() + .route("/servers/{server_id}/channels/{channel_id}", + web::get().to(echo)) + }) + .bind(("0.0.0.0", 4382))? + .run() + )?; - App::new() - .app_data(web::Data::new(data.clone())) - .wrap(cors) - .service(api::web()) - }) - .bind((web.url, web.port))? - .run() - .await?; Ok(()) } diff --git a/src/wss.rs b/src/wss.rs new file mode 100644 index 0000000..9f33f10 --- /dev/null +++ b/src/wss.rs @@ -0,0 +1,40 @@ +use actix_web::{rt, web, Error, HttpRequest, HttpResponse}; +use actix_ws::AggregatedMessage; +use futures_util::StreamExt as _; + +pub async fn echo(req: HttpRequest, stream: web::Payload) -> Result { + let (res, mut session, stream) = actix_ws::handle(&req, stream)?; + + let mut stream = stream + .aggregate_continuations() + // aggregate continuation frames up to 1MiB + .max_continuation_size(2_usize.pow(20)); + + // start task but don't wait for it + rt::spawn(async move { + // receive messages from websocket + while let Some(msg) = stream.next().await { + match msg { + Ok(AggregatedMessage::Text(text)) => { + // echo text message + session.text(text).await.unwrap(); + } + + Ok(AggregatedMessage::Binary(bin)) => { + // echo binary message + session.binary(bin).await.unwrap(); + } + + Ok(AggregatedMessage::Ping(msg)) => { + // respond to PING frame with PONG frame + session.pong(&msg).await.unwrap(); + } + + _ => {} + } + } + }); + + // respond immediately with response connected to WS session + Ok(res) +} \ No newline at end of file