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_photo,
133 send_audio,
134 send_document,
135 send_video,
136 send_animation,
137 send_voice,
138 send_video_note,
139 send_paid_media,
140 send_media_group,
141 send_location,
142 edit_message_live_location,
143 edit_message_live_location_inline,
144 stop_message_live_location,
145 stop_message_live_location_inline,
146 edit_message_checklist,
147 send_venue,
148 send_contact,
149 send_poll,
150 send_checklist,
151 send_dice,
152 send_chat_action,
153 set_message_reaction,
154 get_user_profile_photos,
155 get_user_profile_audios,
156 set_user_emoji_status,
157 get_file,
158 kick_chat_member,
159 ban_chat_member,
160 unban_chat_member,
161 restrict_chat_member,
162 promote_chat_member,
163 set_chat_administrator_custom_title,
164 set_chat_member_tag,
165 ban_chat_sender_chat,
166 unban_chat_sender_chat,
167 set_chat_permissions,
168 export_chat_invite_link,
169 create_chat_invite_link,
170 edit_chat_invite_link,
171 create_chat_subscription_invite_link,
172 edit_chat_subscription_invite_link,
173 revoke_chat_invite_link,
174 set_chat_photo,
175 delete_chat_photo,
176 set_chat_title,
177 set_chat_description,
178 pin_chat_message,
179 unpin_chat_message,
180 unpin_all_chat_messages,
181 leave_chat,
182 get_chat,
183 get_chat_administrators,
184 get_chat_members_count,
185 get_chat_member_count,
186 get_chat_member,
187 set_chat_sticker_set,
188 delete_chat_sticker_set,
189 get_forum_topic_icon_stickers,
190 create_forum_topic,
191 edit_forum_topic,
192 close_forum_topic,
193 reopen_forum_topic,
194 delete_forum_topic,
195 unpin_all_forum_topic_messages,
196 edit_general_forum_topic,
197 close_general_forum_topic,
198 reopen_general_forum_topic,
199 hide_general_forum_topic,
200 unhide_general_forum_topic,
201 unpin_all_general_forum_topic_messages,
202 answer_callback_query,
203 get_user_chat_boosts,
204 set_my_commands,
205 get_business_connection,
206 get_my_commands,
207 set_my_name,
208 get_my_name,
209 set_my_description,
210 get_my_description,
211 set_my_short_description,
212 get_my_short_description,
213 set_my_profile_photo,
214 remove_my_profile_photo,
215 send_live_photo,
216 get_user_personal_chat_messages,
217 answer_guest_query,
218 get_managed_bot_access_settings,
219 set_managed_bot_access_settings,
220 delete_message_reaction,
221 delete_all_message_reactions,
222 get_managed_bot_token,
223 replace_managed_bot_token,
224 save_prepared_keyboard_button,
225 set_chat_menu_button,
226 get_chat_menu_button,
227 set_my_default_administrator_rights,
228 get_my_default_administrator_rights,
229 delete_my_commands,
230 answer_inline_query,
231 answer_web_app_query,
232 save_prepared_inline_message,
233 edit_message_text,
234 edit_message_text_inline,
235 edit_message_caption,
236 edit_message_caption_inline,
237 edit_message_media,
238 edit_message_media_inline,
239 edit_message_reply_markup,
240 edit_message_reply_markup_inline,
241 stop_poll,
242 approve_suggested_post,
243 decline_suggested_post,
244 delete_message,
245 delete_messages,
246 send_sticker,
247 get_sticker_set,
248 get_custom_emoji_stickers,
249 upload_sticker_file,
250 create_new_sticker_set,
251 add_sticker_to_set,
252 set_sticker_position_in_set,
253 delete_sticker_from_set,
254 replace_sticker_in_set,
255 set_sticker_set_thumbnail,
256 set_custom_emoji_sticker_set_thumbnail,
257 set_sticker_set_title,
258 delete_sticker_set,
259 set_sticker_emoji_list,
260 set_sticker_keywords,
261 set_sticker_mask_position,
262 get_available_gifts,
263 send_gift,
264 send_gift_chat,
265 gift_premium_subscription,
266 verify_user,
267 verify_chat,
268 remove_user_verification,
269 remove_chat_verification,
270 read_business_message,
271 delete_business_messages,
272 set_business_account_name,
273 set_business_account_username,
274 set_business_account_bio,
275 set_business_account_profile_photo,
276 remove_business_account_profile_photo,
277 set_business_account_gift_settings,
278 get_business_account_star_balance,
279 transfer_business_account_stars,
280 get_business_account_gifts,
281 get_user_gifts,
282 get_chat_gifts,
283 convert_gift_to_stars,
284 upgrade_gift,
285 transfer_gift,
286 post_story,
287 repost_story,
288 edit_story,
289 delete_story,
290 send_invoice,
291 create_invoice_link,
292 answer_shipping_query,
293 answer_pre_checkout_query,
294 get_my_star_balance,
295 get_star_transactions,
296 refund_star_payment,
297 edit_user_star_subscription,
298 set_passport_data_errors,
299 send_game,
300 set_game_score,
301 set_game_score_inline,
302 get_game_high_scores,
303 approve_chat_join_request,
304 decline_chat_join_request
305 => fwd_inner, fty
306 }
307}
308
309#[must_use = "Requests are lazy and do nothing unless sent"]
310#[derive(Clone)]
311pub struct TraceRequest<R> {
312 inner: R,
313 settings: Settings,
314}
315
316impl<R> TraceRequest<R>
317where
318 R: Request,
319{
320 fn trace_request(&self)
321 where
322 R::Payload: Debug,
323 {
324 if self.settings.contains(Settings::TRACE_REQUESTS_VERBOSE) {
325 log::trace!(
326 "Sending `{}` request: {:?}",
327 <R::Payload as Payload>::NAME,
328 self.inner.payload_ref()
329 );
330 } else if self.settings.contains(Settings::TRACE_REQUESTS) {
331 log::trace!("Sending `{}` request", R::Payload::NAME);
332 }
333 }
334
335 fn trace_response_fn(&self) -> fn(&Result<Output<R>, R::Err>)
336 where
337 Output<R>: Debug,
338 R::Err: Debug,
339 {
340 if self.settings.contains(Settings::TRACE_RESPONSES_VERBOSE) {
341 |response| {
342 log::trace!("Got response from `{}` request: {:?}", R::Payload::NAME, response)
343 }
344 } else if self.settings.contains(Settings::TRACE_RESPONSES) {
345 |_| log::trace!("Got response from `{}` request", R::Payload::NAME)
346 } else {
347 |_| {}
348 }
349 }
350}
351
352impl<R> HasPayload for TraceRequest<R>
353where
354 R: HasPayload,
355{
356 type Payload = R::Payload;
357
358 fn payload_mut(&mut self) -> &mut Self::Payload {
359 self.inner.payload_mut()
360 }
361
362 fn payload_ref(&self) -> &Self::Payload {
363 self.inner.payload_ref()
364 }
365}
366
367impl<R> Request for TraceRequest<R>
368where
369 R: Request,
370 Output<R>: Debug,
371 R::Err: Debug,
372 R::Payload: Debug,
373{
374 type Err = R::Err;
375
376 type Send = Send<R::Send>;
377
378 type SendRef = Send<R::SendRef>;
379
380 fn send(self) -> Self::Send {
381 self.trace_request();
382
383 Send { trace_fn: self.trace_response_fn(), inner: self.inner.send() }
384 }
385
386 fn send_ref(&self) -> Self::SendRef {
387 self.trace_request();
388
389 Send { trace_fn: self.trace_response_fn(), inner: self.inner.send_ref() }
390 }
391}
392
393impl<R> IntoFuture for TraceRequest<R>
394where
395 R: Request,
396 Output<R>: Debug,
397 R::Err: Debug,
398 R::Payload: Debug,
399{
400 type Output = Result<Output<Self>, <Self as Request>::Err>;
401 type IntoFuture = <Self as Request>::Send;
402
403 fn into_future(self) -> Self::IntoFuture {
404 self.send()
405 }
406}
407
408#[pin_project::pin_project]
409pub struct Send<F>
410where
411 F: Future,
412{
413 trace_fn: fn(&F::Output),
414 #[pin]
415 inner: F,
416}
417
418impl<F> Future for Send<F>
419where
420 F: Future,
421{
422 type Output = F::Output;
423
424 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
425 let this = self.project();
426
427 let ret = ready!(this.inner.poll(cx));
428 (this.trace_fn)(&ret);
429 Poll::Ready(ret)
430 }
431}