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