1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
use std::sync::Arc; #[cfg(all(feature = "tokio_compat", not(feature = "tokio")))] use tokio::time::delay_for as sleep; #[cfg(feature = "tokio")] use tokio::time::sleep; use tokio::{ sync::oneshot::{self, error::TryRecvError, Sender}, time::Duration, }; use crate::{error::Result, http::Http}; /// A struct to start typing in a [`Channel`] for an indefinite period of time. /// /// It indicates that the current user is currently typing in the channel. /// /// Typing is started by using the [`Typing::start`] method /// and stopped by using the [`Typing::stop`] method. /// Note that on some clients, typing may persist for a few seconds after [`Typing::stop`] is called. /// Typing is also stopped when the struct is dropped. /// /// If a message is sent while typing is triggered, the user will stop typing for a brief period /// of time and then resume again until either [`Typing::stop`] is called or the struct is dropped. /// /// This should rarely be used for bots, although it is a good indicator that a /// long-running command is still being processed. /// /// ## Examples /// /// ```rust,no_run /// # use serenity::{http::{Http, Typing}, Result}; /// # use std::sync::Arc; /// # /// # fn long_process() {} /// # fn main() -> Result<()> { /// # let http = Http::default(); /// // Initiate typing (assuming `http` is bound) /// let typing = Typing::start(Arc::new(http), 7)?; /// /// // Run some long-running process /// long_process(); /// /// // Stop typing /// typing.stop(); /// # /// # Ok(()) /// # } /// ``` /// /// [`Channel`]: crate::model::channel::Channel #[derive(Debug)] pub struct Typing(Sender<()>); impl Typing { /// Starts typing in the specified [`Channel`] for an indefinite period of time. /// /// Returns [`Typing`]. To stop typing, you must call the [`Typing::stop`] method on /// the returned [`Typing`] object or wait for it to be dropped. Note that on some /// clients, typing may persist for a few seconds after stopped. /// /// # Errors /// /// Returns an [`Error::Http`] if there is an error. /// /// [`Channel`]: crate::model::channel::Channel /// [`Error::Http`]: crate::error::Error::Http pub fn start(http: Arc<Http>, channel_id: u64) -> Result<Self> { let (sx, mut rx) = oneshot::channel(); tokio::spawn(async move { loop { match rx.try_recv() { Ok(_) | Err(TryRecvError::Closed) => break, _ => (), } http.broadcast_typing(channel_id).await?; // It is unclear for how long typing persists after this method is called. // It is generally assumed to be 7 or 10 seconds, so we use 7 to be safe. sleep(Duration::from_secs(7)).await; } Result::Ok(()) }); Ok(Self(sx)) } /// Stops typing in [`Channel`]. /// /// This should be used to stop typing after it is started using [`Typing::start`]. /// Typing may persist for a few seconds on some clients after this is called. /// /// [`Channel`]: crate::model::channel::Channel pub fn stop(self) -> Option<()> { self.0.send(()).ok() } }