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(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::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(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, 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 Military { world: WorldId, player: PlayerId },
93
94 Player { world: WorldId, player: PlayerId },
96
97 PublicCity { world: WorldId, coord: Coord },
105
106 Report {
108 world: WorldId,
109 report: Box<ReportKind>,
110 },
111
112 Round { world: WorldId, round: Round },
119}
120
121impl fmt::Debug for Event {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 match self {
124 Self::ChatMessage { world, message } => {
125 f.debug_struct("ChatMessage")
126 .field("world", world)
127 .field("message", &message.id())
128 .finish()
129 }
130 Self::City { world, coord } => {
131 f.debug_struct("City")
132 .field("world", world)
133 .field("coord", coord)
134 .finish()
135 }
136 Self::Drop { world } => {
137 f.debug_struct("Drop")
138 .field("world", world)
139 .finish()
140 }
141 Self::Military { world, player } => {
142 f.debug_struct("Military")
143 .field("world", world)
144 .field("player", player)
145 .finish()
146 }
147 Self::Player { world, player } => {
148 f.debug_struct("Player")
149 .field("world", world)
150 .field("player", player)
151 .finish()
152 }
153 Self::PublicCity { world, coord } => {
154 f.debug_struct("PublicCity")
155 .field("world", world)
156 .field("coord", coord)
157 .finish()
158 }
159 Self::Report { world, report } => {
160 f.debug_struct("Report")
161 .field("world", world)
162 .field("report", &report.id())
163 .finish()
164 }
165 Self::Round { world, round } => {
166 f.debug_struct("Round")
167 .field("world", world)
168 .field("round", &round.id())
169 .finish()
170 }
171 }
172 }
173}
174
175impl TryFrom<Bytes> for Event {
176 type Error = Error;
177
178 fn try_from(bytes: Bytes) -> Result<Self> {
179 serde_json::from_slice(&bytes).map_err(|err| {
180 tracing::error!("Failed to deserialize event: {err}");
181 Error::FailedToDeserializeEvent
182 })
183 }
184}
185
186impl TryFrom<Event> for Bytes {
187 type Error = Error;
188
189 fn try_from(event: Event) -> Result<Self> {
190 serde_json::to_vec(&event)
191 .map(Bytes::from)
192 .map_err(|err| {
193 tracing::error!("Failed to serialize event: {err}");
194 Error::FailedToSerializeEvent
195 })
196 }
197}
198
199#[derive(Clone, Debug, PartialEq, Eq)]
200pub enum EventTarget {
201 Broadcast,
202 Player(PlayerId),
203}