Initial implementation of a signaling server using actix-web.
This commit is contained in:
commit
f61d7b2ca6
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug
|
||||
target
|
||||
.DS_Store
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# Generated by cargo mutants
|
||||
# Contains mutation testing data
|
||||
**/mutants.out*/
|
||||
|
||||
# RustRover
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
1785
Cargo.lock
generated
Normal file
1785
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "niom-signaling"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.11.0"
|
||||
actix-ws = "0.3.0"
|
||||
futures-util = "0.3"
|
||||
tokio = { version = "1.44.1", features = ["full"] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.143"
|
||||
env_logger = "0.11.8"
|
||||
80
src/main.rs
Normal file
80
src/main.rs
Normal file
@ -0,0 +1,80 @@
|
||||
use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Result};
|
||||
use futures_util::StreamExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AppState {
|
||||
broadcaster: Arc<broadcast::Sender<SignalingMessage>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
struct SignalingMessage {
|
||||
from: String,
|
||||
to: String,
|
||||
msg_type: String, // "offer", "answer", "ice-candidate", "text", "screen-share"
|
||||
data: String // SDP, ICE, Text, Screen-Share metadata
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
let (tx, _rx) = broadcast::channel::<SignalingMessage>(1000);
|
||||
let app_state = AppState {
|
||||
broadcaster: Arc::new(tx)
|
||||
};
|
||||
|
||||
println!("Server is running on http://localhost:8080");
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.app_data(web::Data::new(app_state.clone()))
|
||||
.route("/ws", web::get().to(websocket_handler))
|
||||
})
|
||||
.bind("127.0.0.1:8080")?
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
||||
async fn websocket_handler(
|
||||
req: HttpRequest,
|
||||
body: web::Payload,
|
||||
data: web::Data<AppState>
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let (response, mut session, mut msg_stream) = actix_ws::handle(&req, body)?;
|
||||
let broadcaster = data.broadcaster.clone();
|
||||
let mut rx = broadcaster.subscribe();
|
||||
|
||||
// Handle incoming messages
|
||||
let broadcaster_clone = broadcaster.clone();
|
||||
actix_web::rt::spawn(async move {
|
||||
while let Some(Ok(msg)) = msg_stream.next().await {
|
||||
match msg {
|
||||
actix_ws::Message::Text(text) => {
|
||||
println!("Received text message: {}", text);
|
||||
if let Ok(signal_msg) = serde_json::from_str::<SignalingMessage>(&text) {
|
||||
// Broadcast the message to all subscribers (group chat)
|
||||
// or handle private messages based on `to` field
|
||||
let _ = broadcaster_clone.send(signal_msg);
|
||||
}
|
||||
}
|
||||
actix_ws::Message::Close(_) => break,
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle outgoing messages
|
||||
actix_web::rt::spawn(async move {
|
||||
while let Ok(msg) = rx.recv().await {
|
||||
if let Ok(json) = serde_json::to_string(&msg) {
|
||||
if session.text(json).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user