use async_compat::CompatExt;
use bevy::{
prelude::{Command, Commands, Resource},
tasks::{IoTaskPool, Task},
};
pub use matchbox_signaling;
use matchbox_signaling::{
Error, SignalingCallbacks, SignalingServer, SignalingServerBuilder, SignalingState,
topologies::{
SignalingTopology,
client_server::{ClientServer, ClientServerCallbacks, ClientServerState},
full_mesh::{FullMesh, FullMeshCallbacks, FullMeshState},
},
};
use std::net::SocketAddr;
#[derive(Debug, Resource)]
#[allow(dead_code)] pub struct MatchboxServer(Task<Result<(), Error>>);
impl<Topology, Cb, S> From<SignalingServerBuilder<Topology, Cb, S>> for MatchboxServer
where
Topology: SignalingTopology<Cb, S>,
Cb: SignalingCallbacks,
S: SignalingState,
{
fn from(value: SignalingServerBuilder<Topology, Cb, S>) -> Self {
MatchboxServer::from(value.build())
}
}
impl From<SignalingServer> for MatchboxServer {
fn from(server: SignalingServer) -> Self {
let task_pool = IoTaskPool::get();
let task = task_pool.spawn(server.serve().compat());
MatchboxServer(task)
}
}
struct StartServer<Topology, Cb, S>(SignalingServerBuilder<Topology, Cb, S>)
where
Topology: SignalingTopology<Cb, S>,
Cb: SignalingCallbacks,
S: SignalingState;
impl<Topology, Cb, S> Command for StartServer<Topology, Cb, S>
where
Topology: SignalingTopology<Cb, S> + Send + 'static,
Cb: SignalingCallbacks,
S: SignalingState,
{
fn apply(self, world: &mut bevy::prelude::World) {
world.insert_resource(MatchboxServer::from(self.0))
}
}
pub trait StartServerExt<
Topology: SignalingTopology<Cb, S>,
Cb: SignalingCallbacks,
S: SignalingState,
>
{
fn start_server(&mut self, builder: SignalingServerBuilder<Topology, Cb, S>);
}
impl<Topology, Cb, S> StartServerExt<Topology, Cb, S> for Commands<'_, '_>
where
Topology: SignalingTopology<Cb, S> + Send + 'static,
Cb: SignalingCallbacks,
S: SignalingState,
{
fn start_server(&mut self, builder: SignalingServerBuilder<Topology, Cb, S>) {
self.queue(StartServer(builder))
}
}
struct StopServer;
impl Command for StopServer {
fn apply(self, world: &mut bevy::prelude::World) {
world.remove_resource::<MatchboxServer>();
}
}
pub trait StopServerExt {
fn stop_server(&mut self);
}
impl StopServerExt for Commands<'_, '_> {
fn stop_server(&mut self) {
self.queue(StopServer)
}
}
impl MatchboxServer {
pub fn full_mesh_builder(
socket_addr: impl Into<SocketAddr>,
) -> SignalingServerBuilder<FullMesh, FullMeshCallbacks, FullMeshState> {
SignalingServer::full_mesh_builder(socket_addr)
}
pub fn client_server_builder(
socket_addr: impl Into<SocketAddr>,
) -> SignalingServerBuilder<ClientServer, ClientServerCallbacks, ClientServerState> {
SignalingServer::client_server_builder(socket_addr)
}
}
#[cfg(test)]
mod tests {
use crate::{
matchbox_signaling::topologies::client_server::{ClientServer, ClientServerState},
prelude::*,
};
use bevy::prelude::*;
use std::net::Ipv4Addr;
fn start_signaling(mut commands: Commands) {
let server: MatchboxServer = SignalingServerBuilder::new(
(Ipv4Addr::UNSPECIFIED, 3536),
ClientServer,
ClientServerState::default(),
)
.into();
commands.insert_resource(server);
}
#[test]
fn start_signaling_without_panics() {
let mut app = App::new();
app.add_plugins(MinimalPlugins)
.add_systems(Startup, start_signaling);
app.update();
}
}