1use std::{
2 fmt::Debug,
3 future::{Future, IntoFuture},
4 pin::Pin,
5 task::{self, Poll},
6};
7
8use futures::ready;
9use url::Url;
10
11use crate::{
12 requests::{HasPayload, Output, Payload, Request, Requester},
13 types::*,
14};
15
16#[derive(Clone, Debug)]
29pub struct Trace<B> {
30 inner: B,
31 settings: Settings,
32}
33
34impl<B> Trace<B> {
35 pub fn new(inner: B, settings: Settings) -> Self {
36 Self { inner, settings }
37 }
38
39 pub fn inner(&self) -> &B {
40 &self.inner
41 }
42
43 pub fn into_inner(self) -> B {
44 self.inner
45 }
46
47 pub fn settings(&self) -> Settings {
48 self.settings.clone()
49 }
50}
51
52bitflags::bitflags! {
53 #[derive(Debug, Clone)]
68 pub struct Settings: u8 {
69 const TRACE_REQUESTS = 1;
71
72 const TRACE_REQUESTS_VERBOSE = (1 << 1) | Self::TRACE_REQUESTS.bits();
76
77 const TRACE_RESPONSES = 1 << 2;
79
80 const TRACE_RESPONSES_VERBOSE = (1 << 3) | Self::TRACE_RESPONSES.bits();
84
85 const TRACE_EVERYTHING = Self::TRACE_REQUESTS.bits() | Self::TRACE_RESPONSES.bits();
89
90 const TRACE_EVERYTHING_VERBOSE = Self::TRACE_REQUESTS_VERBOSE.bits() | Self::TRACE_RESPONSES_VERBOSE.bits();
94 }
95}
96
97macro_rules! fty {
98 ($T:ident) => {
99 TraceRequest<B::$T>
100 };
101}
102
103macro_rules! fwd_inner {
104 ($m:ident $this:ident ($($arg:ident : $T:ty),*)) => {
105 TraceRequest {
106 inner: $this.inner().$m($($arg),*),
107 settings: $this.settings.clone()
108 }
109 };
110}
111
112impl<B> Requester for Trace<B>
113where
114 B: Requester,
115{
116 type Err = B::Err;
117
118 requester_forward! {
119 get_me,
120 log_out,
121 close,
122 get_updates,
123 set_webhook,
124 delete_webhook,
125 get_webhook_info,
126 forward_message,
127 forward_messages,
128 copy_message,
129 copy_messages,
130 send_message,
131 send_message_draft,
132 send_rich_message,
133 send_rich_message_draft,
134 send_photo,
135 send_audio,
136 send_document,
137 send_video,
138 send_animation,
139 send_voice,
140 send_video_note,
141 send_paid_media,
142 send_media_group,
143 send_location,
144 edit_message_live_location,
145 edit_message_live_location_inline,
146 stop_message_live_location,
147 stop_message_live_location_inline,
148 edit_message_checklist,
149 send_venue,
150 send_contact,
151 send_poll,
152 send_checklist,
153 send_dice,
154 send_chat_action,
155 set_message_reaction,
156 get_user_profile_photos,
157 get_user_profile_audios,
158 set_user_emoji_status,
159 get_file,
160 kick_chat_member,
161 ban_chat_member,
162 unban_chat_member,
163 restrict_chat_member,
164 promote_chat_member,
165 set_chat_administrator_custom_title,
166 set_chat_member_tag,
167 ban_chat_sender_chat,
168 unban_chat_sender_chat,
169 set_chat_permissions,
170 export_chat_invite_link,
171 create_chat_invite_link,
172 edit_chat_invite_link,
173 create_chat_subscription_invite_link,
174 edit_chat_subscription_invite_link,
175 revoke_chat_invite_link,
176 set_chat_photo,
177 delete_chat_photo,
178 set_chat_title,
179 set_chat_description,
180 pin_chat_message,
181 unpin_chat_message,
182 unpin_all_chat_messages,
183 leave_chat,
184 get_chat,
185 get_chat_administrators,
186 get_chat_members_count,
187 get_chat_member_count,
188 get_chat_member,
189 set_chat_sticker_set,
190 delete_chat_sticker_set,
191 get_forum_topic_icon_stickers,
192 create_forum_topic,
193 edit_forum_topic,
194 close_forum_topic,
195 reopen_forum_topic,
196 delete_forum_topic,
197 unpin_all_forum_topic_messages,
198 edit_general_forum_topic,
199 close_general_forum_topic,
200 reopen_general_forum_topic,
201 hide_general_forum_topic,
202 unhide_general_forum_topic,
203 unpin_all_general_forum_topic_messages,
204 answer_callback_query,
205 get_user_chat_boosts,
206 set_my_commands,
207 get_business_connection,
208 get_my_commands,
209 set_my_name,
210 get_my_name,
211 set_my_description,
212 get_my_description,
213 set_my_short_description,
214 get_my_short_description,
215 set_my_profile_photo,
216 remove_my_profile_photo,
217 send_live_photo,
218 get_user_personal_chat_messages,
219 answer_guest_query,
220 get_managed_bot_access_settings,
221 set_managed_bot_access_settings,
222 delete_message_reaction,
223 delete_all_message_reactions,
224 get_managed_bot_token,
225 replace_managed_bot_token,
226 save_prepared_keyboard_button,
227 set_chat_menu_button,
228 get_chat_menu_button,
229 set_my_default_administrator_rights,
230 get_my_default_administrator_rights,
231 delete_my_commands,
232 answer_inline_query,
233 answer_web_app_query,
234 save_prepared_inline_message,
235 edit_message_text,
236 edit_message_text_inline,
237 edit_message_caption,
238 edit_message_caption_inline,
239 edit_message_media,
240 edit_message_media_inline,
241 edit_message_reply_markup,
242 edit_message_reply_markup_inline,
243 stop_poll,
244 approve_suggested_post,
245 decline_suggested_post,
246 delete_message,
247 delete_messages,
248 send_sticker,
249 get_sticker_set,
250 get_custom_emoji_stickers,
251 upload_sticker_file,
252 create_new_sticker_set,
253 add_sticker_to_set,
254 set_sticker_position_in_set,
255 delete_sticker_from_set,
256 replace_sticker_in_set,
257 set_sticker_set_thumbnail,
258 set_custom_emoji_sticker_set_thumbnail,
259 set_sticker_set_title,
260 delete_sticker_set,
261 set_sticker_emoji_list,
262 set_sticker_keywords,
263 set_sticker_mask_position,
264 get_available_gifts,
265 send_gift,
266 send_gift_chat,
267 gift_premium_subscription,
268 verify_user,
269 verify_chat,
270 remove_user_verification,
271 remove_chat_verification,
272 read_business_message,
273 delete_business_messages,
274 set_business_account_name,
275 set_business_account_username,
276 set_business_account_bio,
277 set_business_account_profile_photo,
278 remove_business_account_profile_photo,
279 set_business_account_gift_settings,
280 get_business_account_star_balance,
281 transfer_business_account_stars,
282 get_business_account_gifts,
283 get_user_gifts,
284 get_chat_gifts,
285 convert_gift_to_stars,
286 upgrade_gift,
287 transfer_gift,
288 post_story,
289 repost_story,
290 edit_story,
291 delete_story,
292 send_invoice,
293 create_invoice_link,
294 answer_shipping_query,
295 answer_pre_checkout_query,
296 get_my_star_balance,
297 get_star_transactions,
298 refund_star_payment,
299 edit_user_star_subscription,
300 set_passport_data_errors,
301 send_game,
302 set_game_score,
303 set_game_score_inline,
304 get_game_high_scores,
305 approve_chat_join_request,
306 decline_chat_join_request,
307 answer_chat_join_request_query,
308 send_chat_join_request_web_app,
309 edit_ephemeral_message_text,
310 edit_ephemeral_message_media,
311 edit_ephemeral_message_caption,
312 edit_ephemeral_message_reply_markup,
313 delete_ephemeral_message
314 => fwd_inner, fty
315 }
316}
317
318#[must_use = "Requests are lazy and do nothing unless sent"]
319#[derive(Clone)]
320pub struct TraceRequest<R> {
321 inner: R,
322 settings: Settings,
323}
324
325impl<R> TraceRequest<R>
326where
327 R: Request,
328{
329 fn trace_request(&self)
330 where
331 R::Payload: Debug,
332 {
333 if self.settings.contains(Settings::TRACE_REQUESTS_VERBOSE) {
334 log::trace!(
335 "Sending `{}` request: {:?}",
336 <R::Payload as Payload>::NAME,
337 self.inner.payload_ref()
338 );
339 } else if self.settings.contains(Settings::TRACE_REQUESTS) {
340 log::trace!("Sending `{}` request", R::Payload::NAME);
341 }
342 }
343
344 fn trace_response_fn(&self) -> fn(&Result<Output<R>, R::Err>)
345 where
346 Output<R>: Debug,
347 R::Err: Debug,
348 {
349 if self.settings.contains(Settings::TRACE_RESPONSES_VERBOSE) {
350 |response| {
351 log::trace!("Got response from `{}` request: {:?}", R::Payload::NAME, response)
352 }
353 } else if self.settings.contains(Settings::TRACE_RESPONSES) {
354 |_| log::trace!("Got response from `{}` request", R::Payload::NAME)
355 } else {
356 |_| {}
357 }
358 }
359}
360
361impl<R> HasPayload for TraceRequest<R>
362where
363 R: HasPayload,
364{
365 type Payload = R::Payload;
366
367 fn payload_mut(&mut self) -> &mut Self::Payload {
368 self.inner.payload_mut()
369 }
370
371 fn payload_ref(&self) -> &Self::Payload {
372 self.inner.payload_ref()
373 }
374}
375
376impl<R> Request for TraceRequest<R>
377where
378 R: Request,
379 Output<R>: Debug,
380 R::Err: Debug,
381 R::Payload: Debug,
382{
383 type Err = R::Err;
384
385 type Send = Send<R::Send>;
386
387 type SendRef = Send<R::SendRef>;
388
389 fn send(self) -> Self::Send {
390 self.trace_request();
391
392 Send { trace_fn: self.trace_response_fn(), inner: self.inner.send() }
393 }
394
395 fn send_ref(&self) -> Self::SendRef {
396 self.trace_request();
397
398 Send { trace_fn: self.trace_response_fn(), inner: self.inner.send_ref() }
399 }
400}
401
402impl<R> IntoFuture for TraceRequest<R>
403where
404 R: Request,
405 Output<R>: Debug,
406 R::Err: Debug,
407 R::Payload: Debug,
408{
409 type Output = Result<Output<Self>, <Self as Request>::Err>;
410 type IntoFuture = <Self as Request>::Send;
411
412 fn into_future(self) -> Self::IntoFuture {
413 self.send()
414 }
415}
416
417#[pin_project::pin_project]
418pub struct Send<F>
419where
420 F: Future,
421{
422 trace_fn: fn(&F::Output),
423 #[pin]
424 inner: F,
425}
426
427impl<F> Future for Send<F>
428where
429 F: Future,
430{
431 type Output = F::Output;
432
433 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
434 let this = self.project();
435
436 let ret = ready!(this.inner.poll(cx));
437 (this.trace_fn)(&ret);
438 Poll::Ready(ret)
439 }
440}