Implement native UDP transport reliability (#52)
This commit is contained in:
@@ -113,6 +113,7 @@ struct ClientRuntime {
|
||||
state: AtomicU8,
|
||||
cancellation: CancellationTokenSource,
|
||||
services: Mutex<Vec<ServiceRegistration>>,
|
||||
agent_throttle_sender: Mutex<Option<Arc<dyn crate::udp_transport::AgentThrottleSender>>>,
|
||||
shutdown_complete: Condvar,
|
||||
shutdown_wait: Mutex<()>,
|
||||
}
|
||||
@@ -132,6 +133,7 @@ impl ClientRuntime {
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
agent_throttle_sender: Mutex::new(None),
|
||||
shutdown_complete: Condvar::new(),
|
||||
shutdown_wait: Mutex::new(()),
|
||||
}
|
||||
@@ -200,6 +202,10 @@ impl ClientRuntime {
|
||||
}
|
||||
}
|
||||
services.clear();
|
||||
self.agent_throttle_sender
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
.take();
|
||||
let shutdown_wait = self
|
||||
.shutdown_wait
|
||||
.lock()
|
||||
@@ -257,6 +263,41 @@ impl GridClient {
|
||||
self.runtime.register(service)
|
||||
}
|
||||
|
||||
/// Installs the network-owned callback used by mapped `AgentThrottle.Set`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Registration fails after client shutdown begins.
|
||||
pub fn set_agent_throttle_sender(
|
||||
&mut self,
|
||||
sender: Arc<dyn crate::udp_transport::AgentThrottleSender>,
|
||||
) -> Result<(), ClientCoreError> {
|
||||
let mut registered = self
|
||||
.runtime
|
||||
.agent_throttle_sender
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
let state = self.lifecycle_state();
|
||||
if state != ClientLifecycleState::Active {
|
||||
return Err(ClientCoreError::InvalidLifecycle {
|
||||
operation: "register the agent throttle sender",
|
||||
state,
|
||||
});
|
||||
}
|
||||
*registered = Some(sender);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn agent_throttle_sender(
|
||||
&self,
|
||||
) -> Option<Arc<dyn crate::udp_transport::AgentThrottleSender>> {
|
||||
self.runtime
|
||||
.agent_throttle_sender
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown(&self) -> Result<(), ClientCoreError> {
|
||||
self.runtime.shutdown()
|
||||
}
|
||||
|
||||
@@ -3333,102 +3333,20 @@ impl AgentState {
|
||||
}
|
||||
|
||||
/// C# type: `T:LibreMetaverse.AgentThrottle`.
|
||||
pub struct AgentThrottle;
|
||||
impl AgentThrottle {
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.#ctor(LibreMetaverse.GridClient)`.
|
||||
pub fn new_with_grid_client(client: libremetaverse::GridClient) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.AgentThrottle.#ctor(LibreMetaverse.GridClient)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.#ctor(System.Byte[],System.Int32)`.
|
||||
pub fn new_with_bytes_int32(data: Vec<u8>, pos: i32) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.AgentThrottle.#ctor(System.Byte[],System.Int32)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.Set`.
|
||||
pub fn set_with_method(&self) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented("M:LibreMetaverse.AgentThrottle.Set")
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.Set(LibreMetaverse.Simulator)`.
|
||||
pub fn set_with_simulator(
|
||||
&self,
|
||||
simulator: Option<libremetaverse::Simulator>,
|
||||
) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.AgentThrottle.Set(LibreMetaverse.Simulator)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.ToBytes`.
|
||||
pub fn to_bytes(&self) -> Result<Vec<u8>, crate::Error> {
|
||||
libremetaverse_types::not_implemented("M:LibreMetaverse.AgentThrottle.ToBytes")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Asset`.
|
||||
pub fn asset(&self) -> f32 {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Asset")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.AgentThrottle.Asset`.
|
||||
pub fn set_asset(&mut self, value: f32) {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Asset")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Cloud`.
|
||||
pub fn cloud(&self) -> f32 {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Cloud")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.AgentThrottle.Cloud`.
|
||||
pub fn set_cloud(&mut self, value: f32) {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Cloud")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Land`.
|
||||
pub fn land(&self) -> f32 {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Land")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.AgentThrottle.Land`.
|
||||
pub fn set_land(&mut self, value: f32) {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Land")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Resend`.
|
||||
pub fn resend(&self) -> f32 {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Resend")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.AgentThrottle.Resend`.
|
||||
pub fn set_resend(&mut self, value: f32) {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Resend")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Task`.
|
||||
pub fn task(&self) -> f32 {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Task")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.AgentThrottle.Task`.
|
||||
pub fn set_task(&mut self, value: f32) {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Task")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Texture`.
|
||||
pub fn texture(&self) -> f32 {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Texture")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.AgentThrottle.Texture`.
|
||||
pub fn set_texture(&mut self, value: f32) {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Texture")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Total`.
|
||||
pub fn total(&self) -> f32 {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Total")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.AgentThrottle.Total`.
|
||||
pub fn set_total(&mut self, value: f32) {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Total")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Wind`.
|
||||
pub fn wind(&self) -> f32 {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Wind")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.AgentThrottle.Wind`.
|
||||
pub fn set_wind(&mut self, value: f32) {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.AgentThrottle.Wind")
|
||||
}
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.#ctor(LibreMetaverse.GridClient)`.
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.#ctor(System.Byte[],System.Int32)`.
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.Set`.
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.Set(LibreMetaverse.Simulator)`.
|
||||
/// C# member: `M:LibreMetaverse.AgentThrottle.ToBytes`.
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Asset`.
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Cloud`.
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Land`.
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Resend`.
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Task`.
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Texture`.
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Total`.
|
||||
/// C# member: `P:LibreMetaverse.AgentThrottle.Wind`.
|
||||
pub use crate::udp_transport::AgentThrottle;
|
||||
|
||||
/// C# type: `T:LibreMetaverse.AgentWearablesReplyEventArgs`.
|
||||
pub struct AgentWearablesReplyEventArgs;
|
||||
@@ -13666,21 +13584,9 @@ pub enum ImageType {
|
||||
}
|
||||
|
||||
/// C# type: `T:LibreMetaverse.IncomingPacketIDCollection`.
|
||||
pub struct IncomingPacketIDCollection;
|
||||
impl IncomingPacketIDCollection {
|
||||
/// C# member: `M:LibreMetaverse.IncomingPacketIDCollection.#ctor(System.Int32)`.
|
||||
pub fn new(capacity: i32) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.IncomingPacketIDCollection.#ctor(System.Int32)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.IncomingPacketIDCollection.TryEnqueue(System.UInt32)`.
|
||||
pub fn try_enqueue(&self, ack: u32) -> bool {
|
||||
libremetaverse_types::unimplemented_api!(
|
||||
"M:LibreMetaverse.IncomingPacketIDCollection.TryEnqueue(System.UInt32)"
|
||||
)
|
||||
}
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.IncomingPacketIDCollection.#ctor(System.Int32)`.
|
||||
/// C# member: `M:LibreMetaverse.IncomingPacketIDCollection.TryEnqueue(System.UInt32)`.
|
||||
pub use crate::udp_transport::IncomingPacketIDCollection;
|
||||
|
||||
/// C# type: `T:LibreMetaverse.InitiateDownloadEventArgs`.
|
||||
pub struct InitiateDownloadEventArgs;
|
||||
@@ -27995,106 +27901,26 @@ pub use crate::foliage_catalog::TreeDefinition;
|
||||
pub use crate::foliage_catalog::TreeDefinitions;
|
||||
|
||||
/// C# type: `T:LibreMetaverse.UDPBase`.
|
||||
pub struct UDPBase;
|
||||
impl UDPBase {
|
||||
/// C# member: `M:LibreMetaverse.UDPBase.AsyncBeginSend(LibreMetaverse.UDPPacketBuffer)`.
|
||||
pub fn async_begin_send(
|
||||
&self,
|
||||
buf: libremetaverse::UDPPacketBuffer,
|
||||
) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.UDPBase.AsyncBeginSend(LibreMetaverse.UDPPacketBuffer)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPBase.Start`.
|
||||
pub fn start(&self) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented("M:LibreMetaverse.UDPBase.Start")
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPBase.Stop`.
|
||||
pub fn stop(&self) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented("M:LibreMetaverse.UDPBase.Stop")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.UDPBase.IsRunning`.
|
||||
pub fn is_running(&self) -> bool {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.UDPBase.IsRunning")
|
||||
}
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPBase.AsyncBeginSend(LibreMetaverse.UDPPacketBuffer)`.
|
||||
/// C# member: `M:LibreMetaverse.UDPBase.Start`.
|
||||
/// C# member: `M:LibreMetaverse.UDPBase.Stop`.
|
||||
/// C# member: `P:LibreMetaverse.UDPBase.IsRunning`.
|
||||
pub use crate::udp_transport::UDPBase;
|
||||
|
||||
/// C# type: `T:LibreMetaverse.UDPPacketBuffer`.
|
||||
pub struct UDPPacketBuffer {
|
||||
/// C# member: `F:LibreMetaverse.UDPPacketBuffer.Data`.
|
||||
pub data: Vec<u8>,
|
||||
/// C# member: `F:LibreMetaverse.UDPPacketBuffer.DataLength`.
|
||||
pub data_length: i32,
|
||||
/// C# member: `F:LibreMetaverse.UDPPacketBuffer.RemoteEndPoint`.
|
||||
pub remote_end_point: std::net::SocketAddr,
|
||||
}
|
||||
impl UDPPacketBuffer {
|
||||
/// C# member: `F:LibreMetaverse.UDPPacketBuffer.DEFAULT_BUFFER_SIZE`.
|
||||
pub const DEFAULT_BUFFER_SIZE: i32 = 4096;
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor`.
|
||||
pub fn new_with_constructor() -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented("M:LibreMetaverse.UDPPacketBuffer.#ctor")
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Byte[],System.Int32,System.Net.IPEndPoint,System.Int32)`.
|
||||
pub fn new_with_bytes_int32_ip_end_point_int32(
|
||||
buffer: Vec<u8>,
|
||||
buffer_size: i32,
|
||||
destination: std::net::SocketAddr,
|
||||
category: i32,
|
||||
) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Byte[],System.Int32,System.Net.IPEndPoint,System.Int32)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Net.IPEndPoint)`.
|
||||
pub fn new_with_ip_end_point(end_point: std::net::SocketAddr) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Net.IPEndPoint)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Net.IPEndPoint,System.Byte[])`.
|
||||
pub fn new_with_ip_end_point_bytes(
|
||||
end_point: std::net::SocketAddr,
|
||||
data: Vec<u8>,
|
||||
) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Net.IPEndPoint,System.Byte[])",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Net.IPEndPoint,System.Int32)`.
|
||||
pub fn new_with_ip_end_point_int32(
|
||||
end_point: std::net::SocketAddr,
|
||||
buffer_size: i32,
|
||||
) -> Result<Self, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Net.IPEndPoint,System.Int32)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.CopyFrom(System.Array)`.
|
||||
pub fn copy_from_with_array(
|
||||
&self,
|
||||
src: libremetaverse_types::compat::Array,
|
||||
) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.UDPPacketBuffer.CopyFrom(System.Array)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.CopyFrom(System.Array,System.Int32)`.
|
||||
pub fn copy_from_with_array_int32(
|
||||
&self,
|
||||
src: libremetaverse_types::compat::Array,
|
||||
length: i32,
|
||||
) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.UDPPacketBuffer.CopyFrom(System.Array,System.Int32)",
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.ResetEndpoint`.
|
||||
pub fn reset_endpoint(&self) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented("M:LibreMetaverse.UDPPacketBuffer.ResetEndpoint")
|
||||
}
|
||||
}
|
||||
/// C# member: `F:LibreMetaverse.UDPPacketBuffer.DEFAULT_BUFFER_SIZE`.
|
||||
/// C# member: `F:LibreMetaverse.UDPPacketBuffer.Data`.
|
||||
/// C# member: `F:LibreMetaverse.UDPPacketBuffer.DataLength`.
|
||||
/// C# member: `F:LibreMetaverse.UDPPacketBuffer.RemoteEndPoint`.
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor`.
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Byte[],System.Int32,System.Net.IPEndPoint,System.Int32)`.
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Net.IPEndPoint)`.
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Net.IPEndPoint,System.Byte[])`.
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.#ctor(System.Net.IPEndPoint,System.Int32)`.
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.CopyFrom(System.Array)`.
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.CopyFrom(System.Array,System.Int32)`.
|
||||
/// C# member: `M:LibreMetaverse.UDPPacketBuffer.ResetEndpoint`.
|
||||
pub use crate::udp_transport::UDPPacketBuffer;
|
||||
|
||||
/// C# type: `T:LibreMetaverse.UUIDNameReplyEventArgs`.
|
||||
pub struct UUIDNameReplyEventArgs;
|
||||
|
||||
@@ -20,6 +20,7 @@ mod skeleton;
|
||||
#[rustfmt::skip] // Deterministic machine output is formatted by the pinned generator.
|
||||
mod skeleton_catalog;
|
||||
mod targa;
|
||||
mod udp_transport;
|
||||
#[rustfmt::skip] // Deterministic machine output is formatted by the pinned generator.
|
||||
mod visual_catalog;
|
||||
|
||||
@@ -204,6 +205,10 @@ pub use libremetaverse_imaging as imaging_abstractions;
|
||||
pub use libremetaverse_structured_data as structured_data;
|
||||
pub use libremetaverse_types as types;
|
||||
pub use libremetaverse_types::Error;
|
||||
pub use udp_transport::{
|
||||
AgentThrottleSender, UdpPacketHandler, UdpThrottleCategory, UdpTransportConfig,
|
||||
UdpTransportError, UdpTransportStats,
|
||||
};
|
||||
|
||||
/// Rust object-safe view of the C# `InventoryBase` inheritance hierarchy.
|
||||
pub trait InventoryObjectClass: std::any::Any {
|
||||
|
||||
1780
crates/libremetaverse/src/udp_transport.rs
Normal file
1780
crates/libremetaverse/src/udp_transport.rs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user