use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Clone, Debug, Serialize, Deserialize, Event, Message)]
pub struct FleetEvent {
pub event_type: String,
pub data: HashMap<String, String>,
pub timestamp: u64,
}
impl FleetEvent {
pub fn new(event_type: impl Into<String>) -> Self {
Self {
event_type: event_type.into(),
data: HashMap::new(),
timestamp: current_unix_time_secs(),
}
}
pub fn with_data(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.data.insert(key.into(), value.into());
self
}
}
#[derive(Default, Resource)]
pub struct FleetEventBuffer {
events: Vec<FleetEvent>,
}
impl FleetEventBuffer {
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = FleetEvent>,
{
self.events.extend(iter);
}
pub fn take(&mut self) -> Vec<FleetEvent> {
std::mem::take(&mut self.events)
}
}
pub fn forward_serialized_events<T>(
mut reader: MessageReader<T>,
mut fleet_writer: MessageWriter<FleetEvent>,
) where
T: Message + Serialize + Clone + Send + Sync + 'static,
{
for event in reader.read() {
let event_type = std::any::type_name::<T>().to_string();
let (serialized_value, serialization_error) = match serde_json::to_value(event) {
Ok(value) => (value, None),
Err(err) => (Value::Null, Some(err.to_string())),
};
let mut fleet_event = FleetEvent::new(event_type.clone());
match &serialized_value {
Value::Object(map) => {
for (key, value) in map {
fleet_event.data.insert(key.clone(), value_to_string(value));
}
}
Value::Null => {}
other => {
fleet_event
.data
.insert("value".to_string(), value_to_string(other));
}
}
if let Some(err) = &serialization_error {
fleet_event
.data
.insert("serialization_error".to_string(), err.clone());
}
fleet_writer.write(fleet_event);
}
}
pub fn collect_fleet_events(
mut reader: MessageReader<FleetEvent>,
mut buffer: ResMut<FleetEventBuffer>,
) {
let new_events: Vec<FleetEvent> = reader.read().cloned().collect();
if !new_events.is_empty() {
buffer.extend(new_events);
}
}
fn current_unix_time_secs() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
}
fn value_to_string(value: &Value) -> String {
match value {
Value::String(s) => s.clone(),
Value::Null => "null".to_string(),
other => other.to_string(),
}
}