Skip to main content

ronami_core/adaptors/
trace.rs

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/// Trace requests and responses.
17///
18/// This is a tool for debugging.
19///
20/// Depending on [`Settings`] and `log` facade this adaptor may output messages
21/// like these:
22/// ```text
23/// TRACE ronami_core::adaptors::trace > Sending `SendDice` request
24/// TRACE ronami_core::adaptors::trace > Got response from `SendDice` request
25/// TRACE ronami_core::adaptors::trace > Sending `SendDice` request: SendDice { chat_id: Id(0), emoji: Some(Dice), disable_notification: None, reply_to_message_id: None, allow_sending_without_reply: None, reply_markup: None }
26/// TRACE ronami_core::adaptors::trace > Got response from `SendDice` request: Ok(Message { id: 13812, date: 1625926524, chat: Chat { .. }, via_bot: None, kind: Dice(MessageDice { dice: Dice { emoji: Dice, value: 3 } }) })
27/// ```
28#[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    /// [`Trace`] settings that determine what will be logged.
54    ///
55    /// ## Examples
56    ///
57    /// ```
58    /// use ronami_core::adaptors::trace::Settings;
59    ///
60    /// // Trace nothing
61    /// let _ = Settings::empty();
62    /// // Trace only requests
63    /// let _ = Settings::TRACE_REQUESTS;
64    /// // Trace requests verbosely and responses (non verbosely)
65    /// let _ = Settings::TRACE_REQUESTS_VERBOSE | Settings::TRACE_RESPONSES;
66    /// ```
67    #[derive(Debug, Clone)]
68    pub struct Settings: u8 {
69        /// Trace requests (only request kind, e.g. `send_message`)
70        const TRACE_REQUESTS = 1;
71
72        /// Trace requests verbosely (with all parameters).
73        ///
74        /// Implies [`TRACE_REQUESTS`]
75        const TRACE_REQUESTS_VERBOSE = (1 << 1) | Self::TRACE_REQUESTS.bits();
76
77        /// Trace responses (only request kind, e.g. `send_message`)
78        const TRACE_RESPONSES = 1 << 2;
79
80        /// Trace responses verbosely (with full response).
81        ///
82        /// Implies [`TRACE_RESPONSES`]
83        const TRACE_RESPONSES_VERBOSE = (1 << 3) | Self::TRACE_RESPONSES.bits();
84
85        /// Trace everything.
86        ///
87        /// Implies [`TRACE_REQUESTS`] and [`TRACE_RESPONSES`].
88        const TRACE_EVERYTHING = Self::TRACE_REQUESTS.bits() | Self::TRACE_RESPONSES.bits();
89
90        /// Trace everything verbosely.
91        ///
92        /// Implies [`TRACE_REQUESTS_VERBOSE`] and [`TRACE_RESPONSES_VERBOSE`].
93        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}