Expand description
§Rust wrapper for Valve GameNetworkingSockets.
Provides an abstraction over the low-level library. There are multiple advantage to use this abstraction:
- Type safety: most of the low-level structures are wrapped and we leverage the type system to restrict the operations such that they are all safe.
- High level: the library abstract most of the structure in such a way that you don’t have to deal with the low-level FFI plumbering required. The API is idiomatic, pure Rust.
§Example
use gns::{GnsGlobal, GnsSocket, IsCreated};
use std::net::Ipv6Addr;
use std::time::Duration;
// **uwrap** must be banned in production, we use it here to extract the most relevant part of the library.
// Initial the global networking state. Note that this instance must be unique per-process.
let gns_global = GnsGlobal::get().unwrap();
// Create a new [`GnsSocket`], the index type [`IsCreated`] is used to determine the state of the socket.
// The [`GnsSocket::new`] function is only available for the [`IsCreated`] state. This is the initial state of the socket.
let gns_socket = GnsSocket::<IsCreated>::new(gns_global.clone());
// Choose your own port
let port = 9001;
// We now do a transition from [`IsCreated`] to the [`IsClient`] state. The [`GnsSocket::connect`] operation does this transition for us.
// Since we are now using a client socket, we have access to a different set of operations.
let client = gns_socket.connect(Ipv6Addr::LOCALHOST.into(), port).unwrap();
// Now that we initiated a connection, there is three operation we must loop over:
// - polling for new messages
// - polling for connection status change
// - polling for callbacks (low-level callbacks required by the underlying library).
// Important to know, regardless of the type of socket, whether it is in [`IsClient`] or [`IsServer`] state, theses three operations are the same.
// The only difference is that polling for messages and status on the client only act on the client connection, while polling for messages and status on a server yield event for all connected clients.
loop {
// Run the low-level callbacks.
gns_global.poll_callbacks();
// Receive a maximum of 100 messages on the client connection.
// For each messages, print it's payload.
let _actual_nb_of_messages_processed = client.poll_messages::<100>(|message| {
println!("{}", core::str::from_utf8(message.payload()).unwrap());
});
// Don't do anything with events.
// One would check the event for connection status, i.e. doing something when we are connected/disconnected from the server.
let _actual_nb_of_events_processed = client.poll_event::<100>(|_| {
});
// Sleep a little bit.
std::thread::sleep(Duration::from_millis(10))
}
§Note
Every instance of of GnsSocket
has a dangling Weak<SegQueue<GnsConnectionEvent>>
pointer associated due to how polling works. Polling is done globally and may buffer events for already destructed GnsSocket
. We use a weak pointer as user data on client/server connections to push events on GnsGlobal::poll_callbacks
, see the queue
field of IsClient
and IsServer
. For simplicity (we may fix this later), every GnsSocket
has it’s own queue and we accept this pretty small memory leak. If you only ever create one instance for the lifetime of your application, this will have no effect.
Re-exports§
pub use gns_sys as sys;
Structs§
- GnsConnection
- GnsConnection
Event - GnsConnection
Info - GnsConnection
Real Time Lane Status - GnsConnection
Real Time Status - GnsError
- Wrapper around steam [
sys::EResult
]. The library ensure that the wrapped value is not [sys::EResult::k_EResultOK
]. - GnsGlobal
- Wraps the initialization/destruction of the low-level GameNetworkingSockets and associated singletons.
- GnsListen
Socket - Opaque wrapper around the low-level [
sys::HSteamListenSocket
]. - GnsNetwork
Message - Wrapper around the low-level equivalent. This type is used to implements a more type-safe version of messages.
- GnsPoll
Group - Opaque wrapper around the low-level [
sys::HSteamNetPollGroup
]. - GnsSocket
GnsSocket
is the most important structure of this library. This structure is used to create client (GnsSocket<IsClient>
) and server (GnsSocket<IsServer>
) sockets via theGnsSocket::connect
andGnsSocket::listen
functions. The drop implementation make sure that everything related to this structure is correctly freed, except theGnsGlobal
instance and the user has a strong guarantee that all the available operations over the socket are safe.- GnsUtils
- IsClient
- State of a
GnsSocket
that has been determined to be a client, usually via theGnsSocket::connect
call. In this state, the socket hold the data required to receive and send messages. - IsCreated
- Initial state of a
GnsSocket
. This state represent a socket that has not been used as a Server or Client implementation. Consequently, the state is empty. - IsServer
- State of a
GnsSocket
that has been determined to be a server, usually via theGnsSocket::listen
call. In this state, the socket hold the data required to accept connections and poll them for messages. - ToReceive
- ToSend
Enums§
- GnsConfig
- The configuration value used to define configure global variables in
GnsUtils::set_global_config_value
Traits§
- IsReady
- Common functions available for any
GnsSocket
state that is implementing it. Regardless of being a client or server, a ready socket will allow us to query for connection events as well as receive messages. - MayDrop
Type Aliases§
- GnsLane
- A lane is represented by a Priority and a Weight
- GnsLane
Id - A lane Id.
- GnsMessage
Number - A network message number. Simple alias for documentation.
- GnsResult
- Outcome of many functions from this library, basic type alias with steam [
sys::EResult
] as error. If the result is [sys::EResult::k_EResultOK
], the value can safely be wrapped, otherwise we return the error. - Priority
- Lane priority
- Weight
- Lane weight