use crate::chat::ChatMessage;
use crate::continent::Coord;
use crate::error::{Error, Result};
use crate::player::PlayerId;
use crate::report::ReportId;
use crate::round::Round;
use crate::world::config::WorldId;
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use std::fmt;
use strum::Display;
use tokio::sync::broadcast::{Receiver, Sender, channel};
pub type Listener = Receiver<(Bytes, EventTarget)>;
#[derive(Clone)]
pub(crate) struct Emitter {
sender: Sender<(Bytes, EventTarget)>,
}
impl Emitter {
pub fn new(capacity: usize) -> Self {
let (sender, _) = channel(capacity);
Self { sender }
}
pub(crate) fn emit(&self, event: Event, target: EventTarget) -> Result<()> {
tracing::info!(?target, ?event);
let bytes = Bytes::try_from(event)?;
let _ = self.sender.send((bytes, target));
Ok(())
}
pub(crate) fn emit_to(&self, target: PlayerId, event: Event) -> Result<()> {
self.emit(event, EventTarget::Player(target))
}
pub(crate) fn broadcast(&self, event: Event) -> Result<()> {
self.emit(event, EventTarget::Broadcast)
}
pub(crate) fn subscribe(&self) -> Listener {
self.sender.subscribe()
}
}
impl Default for Emitter {
fn default() -> Self {
Self::new(100)
}
}
impl fmt::Debug for Emitter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Emitter")
.field("sender", &self.sender.receiver_count())
.finish()
}
}
#[derive(Clone, Debug, Display, Deserialize, Serialize)]
#[serde(tag = "kind", rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
#[cfg_attr(feature = "typescript", ts(export))]
#[remain::sorted]
pub enum Event {
ChatUpdated {
world: WorldId,
message: ChatMessage,
},
CityUpdated { world: WorldId, coord: Coord },
Drop { world: WorldId },
MilitaryUpdated { world: WorldId, player: PlayerId },
PlayerUpdated { world: WorldId, player: PlayerId },
PublicCityUpdated { world: WorldId, coord: Coord },
Report { world: WorldId, report: ReportId },
RoundUpdated { world: WorldId, round: Round },
}
impl TryFrom<Event> for Bytes {
type Error = Error;
fn try_from(event: Event) -> Result<Self> {
serde_json::to_vec(&event)
.map(Bytes::from)
.map_err(|err| {
tracing::error!("Failed to serialize event: {err}");
Error::FailedToSerializeEvent
})
}
}
impl TryFrom<Bytes> for Event {
type Error = Error;
fn try_from(bytes: Bytes) -> Result<Self> {
serde_json::from_slice(&bytes).map_err(|err| {
tracing::error!("Failed to deserialize event: {err}");
Error::FailedToDeserializeEvent
})
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum EventTarget {
Broadcast,
Player(PlayerId),
}