//! Example server using WebSocket which listens for clients sending strings //! and sends back a string reply. use aeronet_io::server::Server; cfg_if::cfg_if! { if #[cfg(target_family = "wasm")] { fn main() { eprintln!("this example is not available on WASM"); } } else { use { aeronet_io::{ connection::{DisconnectReason, Disconnected, LocalAddr}, SessionEndpoint, Session, }, aeronet_websocket::server::{Identity, ServerConfig, WebSocketServer, WebSocketServerPlugin}, bevy::{log::LogPlugin, prelude::*}, }; fn main() -> AppExit { App::new() .add_plugins((MinimalPlugins, LogPlugin::default(), WebSocketServerPlugin)) .add_systems(Startup, open_server) .add_systems(Update, reply) .add_observer(on_opened) .add_observer(on_connecting) .add_observer(on_connected) .add_observer(on_disconnected) .run() } fn server_config() -> ServerConfig { let identity = Identity::self_signed(["localhost", "127.0.0.1", "::1"]).expect("all given SANs should be valid DNS names"); ServerConfig::builder() .with_bind_default(25566) .with_identity(identity) } fn open_server(mut commands: Commands) { let config = server_config(); commands.spawn_empty().queue(WebSocketServer::open(config)); } fn on_opened(trigger: Trigger, servers: Query<&LocalAddr>) { let server = trigger.entity(); let local_addr = servers.get(server).expect("opened server should have a binding socket `LocalAddr`"); info!("{server} opened on {}", **local_addr); } fn on_connecting(trigger: Trigger, clients: Query<&Parent>) { let client = trigger.entity(); let Ok(server) = clients.get(client).map(Parent::get) else { return; }; info!("{client} connecting to {server}"); } fn on_connected(trigger: Trigger, clients: Query<&Parent>) { let client = trigger.entity(); let Ok(server) = clients.get(client).map(Parent::get) else { return; }; info!("{client} connected to {server}"); } fn on_disconnected(trigger: Trigger, clients: Query<&Parent>) { let client = trigger.entity(); let Ok(server) = clients.get(client).map(Parent::get) else { return; }; match &trigger.event().reason { DisconnectReason::User(reason) => { info!("{client} disconnected from {server} by user: {reason}"); } DisconnectReason::Peer(reason) => { info!("{client} disconnected from {server} by peer: {reason}"); } DisconnectReason::Error(err) => { warn!("{client} disconnected from {server} due to error: {err:#}"); } } } fn reply(mut clients: Query<(Entity, &mut Session), With>) { for (client, mut session) in &mut clients { // explicit deref so we can access disjoint fields let session = &mut *session; for packet in session.recv.drain(..) { let msg = String::from_utf8(packet.payload.into()).unwrap_or_else(|_| "(not UTF-8)".into()); info!("{client} > {msg}"); let reply = format!("You sent: {msg}"); info!("{client} < {reply}"); session.send.push(reply.into()); } } } }}