use crate::network::NetworkSendable;
use super::component_registry::SendableComponentRegistry;
use super::messages::{ComponentTypeId, MessageFrame, SceneMessage};
use super::transport::{Transport, TransportConfig, TransportError};
use log::{error, trace};
use std::sync::Arc;
use std::time::{Duration, Instant};
#[derive(Clone)]
pub struct SceneSender {
transport: Option<Arc<dyn Transport>>,
sequence: u64,
frame_number: u64,
config: TransportConfig,
batch_buffer: Vec<SceneMessage>,
in_frame: bool,
last_connect_attempt: Option<Instant>,
connect_retry_interval: Duration,
component_registry: SendableComponentRegistry,
}
impl SceneSender {
pub fn new(config: TransportConfig) -> Self {
Self {
transport: None,
sequence: 0,
frame_number: 0,
config,
batch_buffer: Vec::new(),
in_frame: false,
last_connect_attempt: None,
connect_retry_interval: Duration::from_millis(1000), component_registry: SendableComponentRegistry::default(),
}
}
pub fn set_transport(&mut self, transport: Arc<dyn Transport>) {
self.transport = Some(transport);
}
pub fn start_listening(&mut self) -> Result<(), TransportError> {
use super::transport::TcpServer;
let addr = format!("{}:{}", self.config.address, self.config.port);
let tcp_server = TcpServer::new(&addr)?;
tcp_server.listen()?;
self.set_transport(Arc::new(tcp_server));
Ok(())
}
pub fn try_connect_to_receiver(&mut self) {
if let Some(ref transport) = self.transport {
if let Err(e) = transport.connect() {
trace!("Connection attempt failed: {e}");
}
}
}
fn should_attempt_reconnect(&self) -> bool {
if self.is_connected() {
return false;
}
match self.last_connect_attempt {
None => true, Some(last_attempt) => last_attempt.elapsed() >= self.connect_retry_interval,
}
}
fn maybe_reconnect(&mut self) {
if self.should_attempt_reconnect() {
self.last_connect_attempt = Some(Instant::now());
if let Some(ref transport) = self.transport {
if let Err(e) = transport.connect() {
trace!("Connection attempt failed: {e}");
}
}
}
}
pub fn registry(&self) -> &SendableComponentRegistry {
&self.component_registry
}
pub fn registry_mut(&mut self) -> &mut SendableComponentRegistry {
&mut self.component_registry
}
pub fn is_enabled(&self) -> bool {
self.transport.is_some()
}
pub fn is_connected(&self) -> bool {
if let Some(ref t) = self.transport {
return t.is_connected();
}
false
}
pub fn frame_number(&self) -> u64 {
self.frame_number
}
pub fn start_frame(&mut self) {
let frame_num = self.frame_number;
self.frame_number += 1;
self.in_frame = true;
self.send_message_immediate(SceneMessage::FrameBegin { frame_number: frame_num });
}
pub fn end_frame(&mut self) {
if !self.in_frame {
return;
}
let frame_num = self.frame_number.saturating_sub(1);
self.in_frame = false;
let messages: Vec<SceneMessage> = std::mem::take(&mut self.batch_buffer);
if !messages.is_empty() {
let batch = if messages.len() == 1 {
messages.into_iter().next().unwrap()
} else {
SceneMessage::Batch(messages)
};
self.send_message_immediate(batch);
}
self.send_message_immediate(SceneMessage::FrameEnd { frame_number: frame_num });
}
fn send_message_immediate(&mut self, message: SceneMessage) {
if !self.is_enabled() {
return;
}
self.maybe_reconnect();
let sequence = self.sequence;
self.sequence += 1;
let frame = MessageFrame::new(sequence, message);
if let Some(ref t) = self.transport {
match t.send(&frame) {
Ok(()) => {
trace!("Sent message with sequence {sequence}");
}
Err(TransportError::NotConnected | TransportError::ConnectionClosed) => {
trace!("Message dropped - no receiver connected");
}
Err(e) => {
error!("Failed to send message: {e}"); }
}
} else {
trace!("Message dropped - no transport configured");
}
}
pub fn send_message(&mut self, message: SceneMessage) {
if !self.is_enabled() {
return;
}
if self.in_frame {
self.batch_buffer.push(message);
return;
}
self.send_message_immediate(message);
}
pub fn send_entity_spawn(&mut self, name: &str, is_renderable: bool, is_on_gui: bool) {
let message = SceneMessage::EntitySpawn {
entity_name: name.to_string(),
is_renderable,
is_on_gui,
};
self.send_message(message);
}
pub fn component_registry(&self) -> &SendableComponentRegistry {
&self.component_registry
}
pub fn component_registry_mut(&mut self) -> &mut SendableComponentRegistry {
&mut self.component_registry
}
pub fn is_component_sendable<T: 'static>(&self) -> bool {
self.component_registry.is_network_sendable::<T>()
}
pub fn try_serialize_component(&self, type_id: &ComponentTypeId, component: &dyn std::any::Any) -> Option<Box<dyn NetworkSendable>> {
self.component_registry.try_serialize_component(type_id, component)
}
#[allow(clippy::needless_pass_by_value)]
pub fn send_component(&mut self, entity_name: &str, component: Box<dyn NetworkSendable>) -> Result<(), TransportError> {
let data = component.serialize_to_bytes().map_err(TransportError::Serialization)?;
let message = SceneMessage::ComponentInsert {
entity_name: entity_name.to_string(),
component_type: component.component_type_id(),
data,
};
self.send_message(message);
Ok(())
}
pub fn close(&mut self) {
if let Some(ref t) = self.transport {
t.close();
}
}
}
impl Default for SceneSender {
fn default() -> Self {
Self::new(TransportConfig::default())
}
}
impl Drop for SceneSender {
fn drop(&mut self) {
self.close();
}
}