Skip to main content

td_client/
client.rs

1//! Detached request client for concurrent Telegram operations.
2//!
3//! Obtain a cloneable [`Client`] from [`Session::client`](crate::session::Session::client).
4//! Clients issue requests concurrently without borrowing update consumption.
5//!
6//! Direct function calls use [`Client::send`]. Normal message sends with terminal
7//! delivery tracking use [`Client::track`] and [`Client::track_all`]. File
8//! downloads use [`Client::download`].
9
10use std::sync::{Arc, Weak};
11
12use td_types::traits::Function;
13
14use crate::connection::Connection;
15use crate::error::{Error, Result};
16
17/// A cloneable, non-owning capability for requests to one [`Session`](crate::session::Session).
18///
19/// Clones refer to the same session and may submit requests concurrently. They
20/// cannot receive updates or initiate graceful closure. Keeping a client alive
21/// does not keep the session operational: requests after owner loss or closure
22/// admission fail with [`Error::Disconnected`].
23///
24/// Methods are asynchronous and do not submit until their futures are polled.
25#[derive(Debug, Clone)]
26pub struct Client(pub(crate) Weak<Connection>);
27
28impl Client {
29  /// Sends a generated function and returns its direct `TDLib` response.
30  ///
31  /// `F::Return` is supplied by `td-types::traits::Function`. This is the general
32  /// entry point for the generated API, including getters and message edits.
33  /// For normal sends, the direct response can still describe a pending temporary
34  /// message; use [`track`](Self::track) or [`track_all`](Self::track_all) to
35  /// wait for terminal outcomes.
36  ///
37  /// # Errors
38  ///
39  /// Returns [`Error::Json`] for serialization/decoding failures, [`Error::Td`]
40  /// for `TDLib` error responses, and [`Error::Disconnected`] when the session
41  /// cannot accept the request or its reply is abandoned during teardown.
42  ///
43  /// # Cancellation
44  ///
45  /// Dropping this future stops waiting, not the submitted native request.
46  /// A timeout therefore does not establish that a side effect failed to occur.
47  /// Retries and native cancellation are application decisions.
48  ///
49  /// # Examples
50  ///
51  /// ```no_run
52  /// # use td_client::Client;
53  /// # use td_client::Result;
54  /// use td_types::{enums::User, fns};
55  ///
56  /// # async fn identify(client: &Client) -> Result {
57  /// let User::user(user) = client.send(&fns::getMe {}).await?;
58  /// println!("{}", user.first_name);
59  /// # Ok(())
60  /// # }
61  /// ```
62  pub async fn send<F: Function>(&self, request: &F) -> Result<F::Return> {
63    self.connection()?.request(request).await
64  }
65
66  pub(crate) fn connection(&self) -> Result<Arc<Connection>> {
67    self.0.upgrade().ok_or(Error::Disconnected)
68  }
69}