1use std::time::{Duration, Instant};
2
3use async_trait::async_trait;
4
5use crate::{
6 api::Client,
7 error::APIError,
8 models::{clan, player},
9 war::War,
10};
11
12#[async_trait]
13#[allow(unused_variables)]
14pub trait EventHandler {
15 async fn player(&self, old_player: Option<player::Player>, new_player: player::Player) {}
16 async fn clan(&self, old_clan: Option<clan::Clan>, new_clan: clan::Clan) {}
17 async fn war(&self, old_war: Option<War>, new_war: War) {}
18 async fn on_error(&self, error: APIError, tag: String, event_type: EventType);
19}
20
21#[derive(Debug)]
22pub struct EventsListenerBuilder {
23 event_type: Vec<EventType>,
24 client: Client,
25}
26
27#[derive(Debug, Clone)]
28pub enum EventType {
29 Player(String, Instant, Option<player::Player>),
30 Clan(String, Instant, Option<clan::Clan>),
31 War(String, Instant, Option<War>),
32}
33
34impl std::fmt::Display for EventType {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 Self::Player(tag, _, _) => write!(f, "PlayerEvent({tag})"),
38 Self::Clan(tag, _, _) => write!(f, "ClanEvent({tag})"),
39 Self::War(tag, _, _) => write!(f, "WarEvent({tag})"),
40 }
41 }
42}
43
44impl EventsListenerBuilder {
45 #[must_use]
46 pub const fn new(client: Client) -> Self {
47 Self { event_type: vec![], client }
48 }
49
50 #[must_use]
51 pub fn add_clan(mut self, tag: &str) -> Self {
52 self.event_type.push(EventType::Clan(tag.to_string(), Instant::now(), None));
53 self
54 }
55
56 #[must_use]
57 pub fn add_player(mut self, tag: &str) -> Self {
58 self.event_type.push(EventType::Player(tag.to_string(), Instant::now(), None));
59 self
60 }
61
62 #[must_use]
63 pub fn add_war(mut self, tag: &str) -> Self {
64 self.event_type.push(EventType::War(tag.to_string(), Instant::now(), None));
65 self
66 }
67
68 #[must_use]
69 pub fn add_clans(mut self, tags: Vec<impl ToString>) -> Self {
70 for tag in tags {
72 self.event_type.push(EventType::Clan(tag.to_string(), Instant::now(), None));
73 }
74 self
75 }
76
77 #[must_use]
78 pub fn add_players(mut self, tags: Vec<impl ToString>) -> Self {
79 for tag in tags {
81 self.event_type.push(EventType::Player(tag.to_string(), Instant::now(), None));
82 }
83
84 self
85 }
86
87 #[must_use]
88 pub fn add_wars(&mut self, tags: Vec<impl ToString>) -> &mut Self {
89 for tag in tags {
91 self.event_type.push(EventType::War(tag.to_string(), Instant::now(), None));
92 }
93 self
94 }
95
96 pub fn build<T>(self, handler: T) -> EventsListener<T>
97 where
98 T: EventHandler + Sync + Send,
99 {
100 EventsListener { event_type: self.event_type, client: self.client, handler }
101 }
102}
103
104pub struct EventsListener<T>
105where
106 T: EventHandler + Sync + Send,
107{
108 event_type: Vec<EventType>,
109 client: Client,
110 handler: T,
111}
112
113pub struct EventsError {
114 api_error: APIError,
115 tag: String,
116 event_type: EventType,
117 index: usize,
118}
119
120impl std::fmt::Display for EventsError {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(f, "Error while handling event `{}`: [{}]", self.event_type, self.api_error)
123 }
124}
125
126impl std::fmt::Debug for EventsError {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 write!(f, "Error while handling event `{}`: [{}]", self.event_type, self.api_error)
129 }
130}
131
132impl std::error::Error for EventsError {}
133
134impl<T> EventsListener<T>
135where
136 T: EventHandler + Sync + Send,
137{
138 pub async fn start(mut self, duration: Option<Duration>) -> Result<(), EventsError> {
144 if let Some(duration) = duration {
145 let start = Instant::now();
146 while start.elapsed() < duration {
147 if let Err(e) = self.fire_events().await {
148 self.event_type.remove(e.index);
149 self.handler.on_error(e.api_error, e.tag, e.event_type).await;
150 };
151 }
152 } else {
153 loop {
154 if let Err(e) = self.fire_events().await {
155 self.event_type.remove(e.index);
156 self.handler.on_error(e.api_error, e.tag, e.event_type).await;
157 };
158 }
159 }
160
161 Ok(())
162 }
163
164 #[inline(always)]
165 const fn should_fire_again(duration: Duration, seconds: u64) -> bool {
166 duration.as_secs() >= seconds
167 }
168
169 async fn fire_events(&mut self) -> Result<bool, EventsError> {
175 for (i, event) in self.event_type.iter().enumerate() {
176 match event {
177 EventType::Player(tag, last_fired, old) => {
178 if let Some(duration) = Instant::now().checked_duration_since(*last_fired) {
179 if Self::should_fire_again(duration, 10) {
180 return match self.client.get_player(tag).await {
181 Ok(new) => {
182 self.handler.player(old.clone(), new.clone()).await; self.event_type[i] =
184 EventType::Player(tag.clone(), Instant::now(), Some(new));
185 Ok(true)
186 }
187 Err(err) => Err(EventsError {
188 api_error: err,
189 tag: tag.clone(),
190 event_type: event.clone(),
191 index: i,
192 }),
193 };
194 }
195 };
196 }
197 EventType::Clan(tag, last_fired, old) => {
198 if let Some(duration) = Instant::now().checked_duration_since(*last_fired) {
199 if Self::should_fire_again(duration, 10) {
200 return match self.client.get_clan(tag).await {
201 Ok(new) => {
202 self.handler.clan(old.clone(), new.clone()).await; self.event_type[i] =
204 EventType::Clan(tag.clone(), Instant::now(), Some(new));
205 Ok(true)
206 }
207 Err(err) => Err(EventsError {
208 api_error: err,
209 tag: tag.clone(),
210 event_type: event.clone(),
211 index: i,
212 }),
213 };
214 }
215 };
216 }
217 EventType::War(tag, last_fired, old) => {
218 if let Some(duration) = Instant::now().checked_duration_since(*last_fired) {
219 if Self::should_fire_again(duration, 60 * 10) {
220 return match self.client.get_current_war(tag).await {
221 Ok(new) => {
222 self.handler.war(old.clone(), new.clone()).await; self.event_type[i] =
224 EventType::War(tag.clone(), Instant::now(), Some(new));
225 Ok(true)
226 }
227 Err(err) => Err(EventsError {
228 api_error: err,
229 tag: tag.clone(),
230 event_type: event.clone(),
231 index: i,
232 }),
233 };
234 }
235 };
236 }
237 }
238 }
239
240 Ok(false)
241 }
242}