bones_framework/networking/
online_matchmaking.rs

1#![allow(missing_docs)]
2
3use super::online::{
4    MatchmakerConnectionState, OnlineMatchmakerRequest, OnlineMatchmakerResponse,
5    READ_TO_END_BYTE_COUNT,
6};
7use crate::{
8    networking::{socket::establish_peer_connections, NetworkMatchSocket},
9    prelude::*,
10    utils::BiChannelServer,
11};
12use bones_matchmaker_proto::{MatchInfo, MatchmakerRequest, MatchmakerResponse};
13use std::sync::Arc;
14use tracing::{info, warn};
15
16/// Resolves the search for a match by sending a matchmaking request and handling responses.
17pub(crate) async fn resolve_search_for_match(
18    matchmaker_channel: &BiChannelServer<OnlineMatchmakerRequest, OnlineMatchmakerResponse>,
19    matchmaker_connection_state: &mut MatchmakerConnectionState,
20    match_info: MatchInfo,
21) -> anyhow::Result<()> {
22    let conn = matchmaker_connection_state.acquire_connection().await?;
23    let (mut send, mut recv) = conn.open_bi().await?;
24
25    // Send a matchmaking request to the server
26    let message = MatchmakerRequest::RequestMatchmaking(match_info.clone());
27    info!(request=?message, "Resolve: Sending match request");
28    let message = postcard::to_allocvec(&message)?;
29    send.write_all(&message).await?;
30    send.finish()?;
31    send.stopped().await?;
32
33    let res = recv.read_to_end(READ_TO_END_BYTE_COUNT).await?;
34    let _response: MatchmakerResponse = postcard::from_bytes(&res)?;
35
36    loop {
37        tokio::select! {
38            message = matchmaker_channel.recv() => {
39                match message {
40                    Ok(OnlineMatchmakerRequest::StopSearch { .. }) => {
41                        if let Err(err) = resolve_stop_search_for_match(
42                            matchmaker_channel,
43                            matchmaker_connection_state,
44                            match_info.clone(),
45                        ).await {
46                            warn!("Error stopping matchmaking: {:?}", err);
47                        }
48                        return Ok(());
49                    }
50                    Ok(other) => {
51                        warn!("Unexpected request during matchmaking: {:?}", other);
52                    }
53                    Err(err) => {
54                        anyhow::bail!("Failed to recv from match maker channel: {err:?}");
55                    }
56                }
57            }
58            recv = conn.accept_uni() => {
59                let mut recv = recv?;
60                let message = recv.read_to_end(5 * 1024).await?;
61                let message: MatchmakerResponse = postcard::from_bytes(&message)?;
62
63                match message {
64                    MatchmakerResponse::MatchmakingUpdate{ player_count } => {
65                        info!("Online matchmaking updated player count: {player_count}");
66                        matchmaker_channel.try_send(OnlineMatchmakerResponse::MatchmakingUpdate{ player_count })?;
67                    }
68                    MatchmakerResponse::Success {
69                        random_seed,
70                        player_idx,
71                        player_count,
72                        player_ids,
73                    } => {
74                        info!(%random_seed, %player_idx, player_count=%player_count, "Online match starting");
75
76                        let peer_connections = establish_peer_connections(
77                            player_idx,
78                            player_count,
79                            player_ids,
80                            None,
81                        )
82                        .await?;
83
84                        let socket = super::socket::Socket::new(player_idx, peer_connections);
85
86                        matchmaker_channel.try_send(OnlineMatchmakerResponse::GameStarting {
87                            socket: NetworkMatchSocket(Arc::new(socket)),
88                            player_idx: player_idx as _,
89                            player_count: player_count as _,
90                            random_seed
91                        })?;
92
93                        matchmaker_connection_state.close_connection();
94                        return Ok(());
95                    }
96                    other => anyhow::bail!("Unexpected message from matchmaker: {other:?}"),
97                }
98            }
99        }
100    }
101}
102
103/// Resolves the stop search for a match by sending a stop matchmaking request and handling responses.
104pub(crate) async fn resolve_stop_search_for_match(
105    matchmaker_channel: &BiChannelServer<OnlineMatchmakerRequest, OnlineMatchmakerResponse>,
106    matchmaker_connection_state: &mut MatchmakerConnectionState,
107    match_info: MatchInfo,
108) -> anyhow::Result<()> {
109    let conn = matchmaker_connection_state.acquire_connection().await?;
110    // Use the existing connection to send the stop request
111    let (mut send, mut recv) = conn.open_bi().await?;
112
113    let message = MatchmakerRequest::StopMatchmaking(match_info);
114    info!(request=?message, "Sending stop matchmaking request");
115
116    let message = postcard::to_allocvec(&message)?;
117    send.write_all(&message).await?;
118    send.finish()?;
119    send.stopped().await?;
120
121    let res = recv.read_to_end(READ_TO_END_BYTE_COUNT).await?;
122    let response: MatchmakerResponse = postcard::from_bytes(&res)?;
123
124    match response {
125        MatchmakerResponse::Accepted => {
126            matchmaker_channel
127                .send(OnlineMatchmakerResponse::Error(
128                    "Matchmaking stopped by user".to_string(),
129                ))
130                .await?;
131        }
132        MatchmakerResponse::Error(error) => {
133            anyhow::bail!("Failed to stop matchmaking: {}", error);
134        }
135        _ => {
136            anyhow::bail!("Unexpected response from matchmaker: {:?}", response);
137        }
138    }
139
140    Ok(())
141}