Skip to content

Commit

Permalink
refactor: use iroh::protocol::Router to implement the matchmaker
Browse files Browse the repository at this point in the history
  • Loading branch information
dignifiedquire committed Dec 4, 2024
1 parent 957344e commit 3f4ba7a
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 52 deletions.
30 changes: 12 additions & 18 deletions other_crates/bones_matchmaker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
extern crate tracing;

use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::sync::Arc;

use bones_matchmaker_proto::MATCH_ALPN;
use iroh::key::SecretKey;
use matchmaker::Matchmaker;

pub mod cli;
mod helpers;
Expand Down Expand Up @@ -74,24 +76,16 @@ async fn server(args: Config) -> anyhow::Result<()> {

println!("Node ID: {}", my_addr.node_id);

// Listen for incomming connections
while let Some(connecting) = endpoint.accept().await {
let connection = connecting.await;

match connection {
Ok(conn) => {
info!(
connection_id = conn.stable_id(),
addr = ?conn.remote_address(),
"Accepted connection from client"
);

// Spawn a task to handle the new connection
tokio::task::spawn(matchmaker::handle_connection(endpoint.clone(), conn));
}
Err(e) => error!("Error opening client connection: {e:?}"),
}
}
let matchmaker = Matchmaker::new(endpoint.clone());
let router = iroh::protocol::Router::builder(endpoint)
.accept(MATCH_ALPN, Arc::new(matchmaker))
.spawn()
.await?;

// wait for shutdown
tokio::signal::ctrl_c().await?;

router.shutdown().await?;

info!("Server shutdown");

Expand Down
3 changes: 2 additions & 1 deletion other_crates/bones_matchmaker/src/lobbies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub async fn handle_create_lobby(

/// Handles a request to join an existing lobby
pub async fn handle_join_lobby(
ep: Endpoint,
ep: &Endpoint,
conn: Connection,
game_id: GameID,
lobby_id: LobbyId,
Expand Down Expand Up @@ -169,6 +169,7 @@ pub async fn handle_join_lobby(
{
let members = connections.1;
drop(state);
let ep = ep.clone();
tokio::spawn(async move {
if let Err(e) = start_game(ep, members, &match_info).await {
error!("Error starting match from full lobby: {:?}", e);
Expand Down
98 changes: 67 additions & 31 deletions other_crates/bones_matchmaker/src/matchmaker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use bones_matchmaker_proto::{
GameID, LobbyId, LobbyInfo, MatchInfo, MatchmakerRequest, MatchmakerResponse,
PlayerIdxAssignment,
};
use futures::future::BoxFuture;
use iroh::{endpoint::Connection, Endpoint, NodeAddr};
use once_cell::sync::Lazy;
use rand::{prelude::SliceRandom, SeedableRng};
Expand Down Expand Up @@ -34,38 +35,73 @@ pub struct State {
pub static MATCHMAKER_STATE: Lazy<Arc<Mutex<State>>> =
Lazy::new(|| Arc::new(Mutex::new(State::default())));

/// Handles incoming connections and routes requests to appropriate handlers
pub async fn handle_connection(ep: Endpoint, conn: Connection) -> Result<()> {
let connection_id = conn.stable_id();
loop {
tokio::select! {
_ = conn.closed() => {
info!("[{}] Client closed connection.", connection_id);
return Ok(());
#[derive(Debug)]
pub struct Matchmaker {
endpoint: Endpoint,
}

impl iroh::protocol::ProtocolHandler for Matchmaker {
fn accept(self: Arc<Self>, conn: iroh::endpoint::Connecting) -> BoxFuture<'static, Result<()>> {
Box::pin(async move {
let connection = conn.await;

match connection {
Ok(conn) => {
info!(
connection_id = conn.stable_id(),
addr = ?conn.remote_address(),
"Accepted connection from client"
);

// Spawn a task to handle the new connection
self.handle_connection(conn).await?;
}
Err(e) => error!("Error opening client connection: {e:?}"),
}
bi = conn.accept_bi() => {
let (mut send, mut recv) = bi?;
// Parse the incoming request
let request: MatchmakerRequest = postcard::from_bytes(&recv.read_to_end(256).await?)?;

// Route the request to the appropriate handler
match request {
MatchmakerRequest::RequestMatchmaking(match_info) => {
handle_request_matchaking(ep.clone(), conn.clone(), match_info, &mut send).await?;
send.finish()?;
send.stopped().await?;
}
MatchmakerRequest::StopMatchmaking(match_info) => {
handle_stop_matchmaking(conn.clone(), match_info, &mut send).await?;
}
MatchmakerRequest::ListLobbies(game_id) => {
handle_list_lobbies(game_id, &mut send).await?;
}
MatchmakerRequest::CreateLobby(lobby_info) => {
handle_create_lobby(conn.clone(), lobby_info, &mut send).await?;
}
MatchmakerRequest::JoinLobby(game_id, lobby_id, password) => {
handle_join_lobby(ep.clone(), conn.clone(), game_id, lobby_id, password, &mut send).await?;

Ok(())
})
}
}

impl Matchmaker {
pub fn new(endpoint: Endpoint) -> Self {
Matchmaker { endpoint }
}

/// Handles incoming connections and routes requests to appropriate handlers
async fn handle_connection(&self, conn: Connection) -> Result<()> {
let connection_id = conn.stable_id();
loop {
tokio::select! {
_ = conn.closed() => {
info!("[{}] Client closed connection.", connection_id);
return Ok(());
}
bi = conn.accept_bi() => {
let (mut send, mut recv) = bi?;
// Parse the incoming request
let request: MatchmakerRequest = postcard::from_bytes(&recv.read_to_end(256).await?)?;

// Route the request to the appropriate handler
match request {
MatchmakerRequest::RequestMatchmaking(match_info) => {
handle_request_matchaking(&self.endpoint, conn.clone(), match_info, &mut send).await?;
send.finish()?;
send.stopped().await?;
}
MatchmakerRequest::StopMatchmaking(match_info) => {
handle_stop_matchmaking(conn.clone(), match_info, &mut send).await?;
}
MatchmakerRequest::ListLobbies(game_id) => {
handle_list_lobbies(game_id, &mut send).await?;
}
MatchmakerRequest::CreateLobby(lobby_info) => {
handle_create_lobby(conn.clone(), lobby_info, &mut send).await?;
}
MatchmakerRequest::JoinLobby(game_id, lobby_id, password) => {
handle_join_lobby(&self.endpoint, conn.clone(), game_id, lobby_id, password, &mut send).await?;
}
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions other_crates/bones_matchmaker/src/matchmaking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub async fn handle_stop_matchmaking(

/// Handles a start matchmaking request from a client
pub async fn handle_request_matchaking(
ep: Endpoint,
ep: &Endpoint,
conn: Connection,
match_info: MatchInfo,
send: &mut iroh::endpoint::SendStream,
Expand Down Expand Up @@ -267,7 +267,7 @@ async fn send_matchmaking_updates(
}

/// Starts a matchmade game if the room is ready with sufficient players
async fn start_matchmaked_game_if_ready(ep: Endpoint, match_info: &MatchInfo) -> Result<()> {
async fn start_matchmaked_game_if_ready(ep: &Endpoint, match_info: &MatchInfo) -> Result<()> {
let members = {
let state = MATCHMAKER_STATE.lock().await;
state
Expand All @@ -279,6 +279,7 @@ async fn start_matchmaked_game_if_ready(ep: Endpoint, match_info: &MatchInfo) ->
if let Some(members) = members {
let cloned_match_info = match_info.clone();
let players_len = members.len();
let ep = ep.clone();
tokio::spawn(async move {
match start_game(ep, members, &cloned_match_info).await {
Ok(_) => info!("Starting matchmaked game with {} players", players_len),
Expand Down

0 comments on commit 3f4ba7a

Please sign in to comment.