1use crate::chat::ChatMessage;
5use crate::continent::coord::Coord;
6use crate::error::{Error, Result};
7use crate::player::PlayerId;
8use crate::report::ReportKind;
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() -> Self {
26 let (sender, _) = channel(100);
27 Self { sender }
28 }
29
30 pub(crate) fn emit(&self, event: Event, target: EventTarget) -> Result<()> {
31 tracing::trace!(?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()
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, 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 ChatMessage {
73 world: WorldId,
74 message: ChatMessage,
75 },
76
77 City { world: WorldId, coord: Coord },
83
84 Drop { world: WorldId },
88
89 Market { world: WorldId },
91
92 Military { world: WorldId, player: PlayerId },
96
97 Player { world: WorldId, player: PlayerId },
99
100 PublicCity { world: WorldId, coord: Coord },
108
109 Report {
111 world: WorldId,
112 report: Box<ReportKind>,
113 },
114
115 Round { world: WorldId, round: Round },
122}
123
124impl fmt::Debug for Event {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 Self::ChatMessage { world, message } => {
128 f.debug_struct("ChatMessage")
129 .field("world", world)
130 .field("message", &message.id())
131 .finish()
132 }
133 Self::City { world, coord } => {
134 f.debug_struct("City")
135 .field("world", world)
136 .field("coord", coord)
137 .finish()
138 }
139 Self::Drop { world } => {
140 f.debug_struct("Drop")
141 .field("world", world)
142 .finish()
143 }
144 Self::Market { world } => {
145 f.debug_struct("Market")
146 .field("world", world)
147 .finish()
148 }
149 Self::Military { world, player } => {
150 f.debug_struct("Military")
151 .field("world", world)
152 .field("player", player)
153 .finish()
154 }
155 Self::Player { world, player } => {
156 f.debug_struct("Player")
157 .field("world", world)
158 .field("player", player)
159 .finish()
160 }
161 Self::PublicCity { world, coord } => {
162 f.debug_struct("PublicCity")
163 .field("world", world)
164 .field("coord", coord)
165 .finish()
166 }
167 Self::Report { world, report } => {
168 f.debug_struct("Report")
169 .field("world", world)
170 .field("report", &report.id())
171 .finish()
172 }
173 Self::Round { world, round } => {
174 f.debug_struct("Round")
175 .field("world", world)
176 .field("round", &round.id())
177 .finish()
178 }
179 }
180 }
181}
182
183impl TryFrom<Bytes> for Event {
184 type Error = Error;
185
186 fn try_from(bytes: Bytes) -> Result<Self> {
187 serde_json::from_slice(&bytes).map_err(|err| {
188 tracing::error!("Failed to deserialize event: {err}");
189 Error::FailedToDeserializeEvent
190 })
191 }
192}
193
194impl TryFrom<Event> for Bytes {
195 type Error = Error;
196
197 fn try_from(event: Event) -> Result<Self> {
198 serde_json::to_vec(&event)
199 .map(Bytes::from)
200 .map_err(|err| {
201 tracing::error!("Failed to serialize event: {err}");
202 Error::FailedToSerializeEvent
203 })
204 }
205}
206
207#[derive(Clone, Debug, PartialEq, Eq)]
208pub enum EventTarget {
209 Broadcast,
210 Player(PlayerId),
211}