1use crate::chat::ChatMessage;
5use crate::continent::Coord;
6use crate::error::{Error, Result};
7use crate::player::PlayerId;
8use crate::report::ReportId;
9use crate::round::Round;
10use crate::world::config::WorldId;
11use bytes::Bytes;
12use serde::{Deserialize, Serialize};
13use std::fmt;
14use strum::Display;
15use tokio::sync::broadcast::{Receiver, Sender, channel};
16
17pub type Listener = Receiver<(Bytes, EventTarget)>;
18
19#[derive(Clone)]
20pub(crate) struct Emitter {
21 sender: Sender<(Bytes, EventTarget)>,
22}
23
24impl Emitter {
25 pub fn new(capacity: usize) -> Self {
26 let (sender, _) = channel(capacity);
27 Self { sender }
28 }
29
30 pub(crate) fn emit(&self, event: Event, target: EventTarget) -> Result<()> {
31 tracing::info!(?target, ?event);
32 let bytes = Bytes::try_from(event)?;
33 let _ = self.sender.send((bytes, target));
34 Ok(())
35 }
36
37 pub(crate) fn emit_to(&self, target: PlayerId, event: Event) -> Result<()> {
38 self.emit(event, EventTarget::Player(target))
39 }
40
41 pub(crate) fn broadcast(&self, event: Event) -> Result<()> {
42 self.emit(event, EventTarget::Broadcast)
43 }
44
45 pub(crate) fn subscribe(&self) -> Listener {
46 self.sender.subscribe()
47 }
48}
49
50impl Default for Emitter {
51 fn default() -> Self {
52 Self::new(100)
53 }
54}
55
56impl fmt::Debug for Emitter {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 f.debug_struct("Emitter")
59 .field("sender", &self.sender.receiver_count())
60 .finish()
61 }
62}
63
64#[derive(Clone, Debug, Display, Deserialize, Serialize)]
65#[serde(tag = "kind", rename_all = "kebab-case")]
66#[strum(serialize_all = "kebab-case")]
67#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
68#[cfg_attr(feature = "typescript", ts(export))]
69#[remain::sorted]
70pub enum Event {
71 ChatUpdated {
73 world: WorldId,
74 message: ChatMessage,
75 },
76
77 CityUpdated { world: WorldId, coord: Coord },
83
84 Drop { world: WorldId },
88
89 MilitaryUpdated { world: WorldId, player: PlayerId },
93
94 PlayerUpdated { world: WorldId, player: PlayerId },
96
97 PublicCityUpdated { world: WorldId, coord: Coord },
105
106 Report { world: WorldId, report: ReportId },
108
109 RoundUpdated { world: WorldId, round: Round },
116}
117
118impl TryFrom<Event> for Bytes {
119 type Error = Error;
120
121 fn try_from(event: Event) -> Result<Self> {
122 serde_json::to_vec(&event)
123 .map(Bytes::from)
124 .map_err(|err| {
125 tracing::error!("Failed to serialize event: {err}");
126 Error::FailedToSerializeEvent
127 })
128 }
129}
130
131impl TryFrom<Bytes> for Event {
132 type Error = Error;
133
134 fn try_from(bytes: Bytes) -> Result<Self> {
135 serde_json::from_slice(&bytes).map_err(|err| {
136 tracing::error!("Failed to deserialize event: {err}");
137 Error::FailedToDeserializeEvent
138 })
139 }
140}
141
142#[derive(Clone, Debug, PartialEq, Eq)]
143pub enum EventTarget {
144 Broadcast,
145 Player(PlayerId),
146}