use crate::WebTransportError;
use aeronet_io::Session;
use aeronet_io::connection::{LocalAddr, PeerAddr};
use aeronet_webtransport::server::{
ServerConfig, SessionRequest, SessionResponse, WebTransportServer, WebTransportServerClient,
};
use aeronet_webtransport::wtransport::Identity;
use bevy_app::{App, Plugin};
use bevy_ecs::{
error::Result,
prelude::{
ChildOf, Commands, Component, Entity, EntityCommand, Name, OnAdd, Query, Trigger, With,
Without, World,
},
};
use core::time::Duration;
use lightyear_aeronet::server::ServerAeronetPlugin;
use lightyear_aeronet::{AeronetLinkOf, AeronetPlugin};
use lightyear_link::prelude::LinkOf;
use lightyear_link::server::Server;
use lightyear_link::{Link, LinkStart, Linked, Linking};
use tracing::info;
pub struct WebTransportServerPlugin;
impl Plugin for WebTransportServerPlugin {
fn build(&self, app: &mut App) {
if !app.is_plugin_added::<AeronetPlugin>() {
app.add_plugins(AeronetPlugin);
}
if !app.is_plugin_added::<ServerAeronetPlugin>() {
app.add_plugins(ServerAeronetPlugin);
}
app.add_plugins(aeronet_webtransport::server::WebTransportServerPlugin);
app.add_observer(Self::link);
app.add_observer(Self::on_session_request);
app.add_observer(Self::on_connection);
}
}
#[derive(Debug, Component)]
#[require(Server)]
pub struct WebTransportServerIo {
pub certificate: Identity,
}
impl WebTransportServerPlugin {
fn link(
trigger: Trigger<LinkStart>,
query: Query<
(Entity, &WebTransportServerIo, Option<&LocalAddr>),
(Without<Linking>, Without<Linked>),
>,
mut commands: Commands,
) -> Result {
if let Ok((entity, io, local_addr)) = query.get(trigger.target()) {
let server_addr = local_addr.ok_or(WebTransportError::LocalAddrMissing)?.0;
let certificate = io.certificate.clone_identity();
commands.queue(move |world: &mut World| {
let config = ServerConfig::builder()
.with_bind_address(server_addr)
.with_identity(certificate)
.keep_alive_interval(Some(Duration::from_secs(1)))
.max_idle_timeout(Some(Duration::from_secs(5)))
.expect("should be a valid idle timeout")
.build();
info!("Server WebTransport starting at {}", server_addr);
let child = world.spawn((AeronetLinkOf(entity), Name::from("WebTransportServer")));
WebTransportServer::open(config).apply(child);
});
}
Ok(())
}
fn on_session_request(mut request: Trigger<SessionRequest>) {
request.respond(SessionResponse::Accepted);
}
fn on_connection(
trigger: Trigger<OnAdd, Session>,
query: Query<&AeronetLinkOf>,
child_query: Query<(&ChildOf, &PeerAddr), With<WebTransportServerClient>>,
mut commands: Commands,
) {
if let Ok((child_of, peer_addr)) = child_query.get(trigger.target()) {
if let Ok(server_link) = query.get(child_of.parent()) {
let link_entity = commands
.spawn((
LinkOf {
server: server_link.0,
},
Link::new(None),
PeerAddr(peer_addr.0),
))
.id();
commands.entity(trigger.target()).insert((
AeronetLinkOf(link_entity),
Name::from("WebTransportClientOf"),
));
}
}
}
}