use crate::networking_sockets::NetConnection;
use crate::networking_types::{
AppNetConnectionEnd, NetConnectionEnd, NetConnectionEvent, NetConnectionStatusChanged,
NetworkingConnectionState,
};
use crate::{register_callback, CallbackHandle, Inner};
use std::sync::{Arc, Weak};
use steamworks_sys as sys;
use sys::ISteamNetworkingSockets;
pub(crate) fn get_or_create_connection_callback(
inner: Arc<Inner>,
sockets: *mut ISteamNetworkingSockets,
) -> Arc<CallbackHandle> {
let mut network_socket_data = inner.networking_sockets_data.lock().unwrap();
if let Some(callback) = network_socket_data.connection_callback.upgrade() {
callback
} else {
let handler = ConnectionCallbackHandler {
inner: Arc::downgrade(&inner),
sockets,
};
let callback = unsafe {
register_callback(&inner, move |event: NetConnectionStatusChanged| {
handler.callback(event);
})
};
let callback = Arc::new(callback);
network_socket_data.connection_callback = Arc::downgrade(&callback);
callback
}
}
pub(crate) struct ConnectionCallbackHandler {
inner: Weak<Inner>,
sockets: *mut ISteamNetworkingSockets,
}
unsafe impl Send for ConnectionCallbackHandler {}
unsafe impl Sync for ConnectionCallbackHandler {}
impl ConnectionCallbackHandler {
pub(crate) fn callback(&self, event: NetConnectionStatusChanged) {
if let Some(socket) = event.connection_info.listen_socket() {
self.listen_socket_callback(socket, event);
} else {
self.independent_connection_callback(event);
}
}
fn listen_socket_callback(
&self,
socket_handle: sys::HSteamListenSocket,
event: NetConnectionStatusChanged,
) {
if let Some(inner) = self.inner.upgrade() {
let data = inner.networking_sockets_data.lock().unwrap();
if let Some((socket, sender)) = data
.sockets
.get(&socket_handle)
.and_then(|(socket, sender)| socket.upgrade().map(|socket| (socket, sender)))
{
let connection_handle = event.connection;
let state = event.connection_info.state().expect("invalid state");
if let Ok(event) = event.into_listen_socket_event(socket) {
if let Err(_err) = sender.send(event) {
if let NetworkingConnectionState::Connecting = state {
self.reject_connection(connection_handle);
}
}
} else {
}
}
}
}
fn reject_connection(&self, connection_handle: sys::HSteamNetConnection) {
if let Some(inner) = self.inner.upgrade() {
NetConnection::new_internal(connection_handle, self.sockets, inner.clone()).close(
NetConnectionEnd::App(AppNetConnectionEnd::generic_normal()).into(),
Some("no new connections will be accepted"),
false,
);
}
}
fn independent_connection_callback(&self, status_changed: NetConnectionStatusChanged) {
let Some(inner) = self.inner.upgrade() else {
return;
};
let data = inner.networking_sockets_data.lock().unwrap();
let Some(sender) = data.independent_connections.get(&status_changed.connection) else {
return;
};
let Ok(new_state) = status_changed.connection_info.state() else {
return;
};
let event = NetConnectionEvent {
new_state,
old_state: status_changed.old_state,
};
if let Err(_r) = sender.send(event) {
}
}
}