1#[doc(hidden)]
3mod observer;
4
5pub mod worker;
7
8#[doc(hidden)]
9mod api;
10pub mod auth_handler;
12
13#[doc(hidden)]
14pub mod tdlib_client;
15
16pub use auth_handler::{
17 AuthStateHandler, AuthStateHandlerProxy, ClientIdentifier, ConsoleAuthStateHandler,
18 SignalAuthStateHandler,
19};
20use observer::OBSERVER;
21use serde::de::DeserializeOwned;
22pub use worker::{Worker, WorkerBuilder};
23
24use crate::client::auth_handler::ClientAuthStateHandler;
25use crate::types::{
26 AuthorizationStateWaitCode, AuthorizationStateWaitEncryptionKey,
27 AuthorizationStateWaitPassword, AuthorizationStateWaitPhoneNumber,
28 AuthorizationStateWaitRegistration, Close, Ok, RFunction, TdlibParameters, Update,
29};
30use crate::{
31 errors::{Error, Result},
32 types::Error as TDLibError,
33 utils,
34};
35use async_trait::async_trait;
36use tdlib_client::{TdJson, TdLibClient};
37use tokio::sync::mpsc;
38
39const CLIENT_NOT_AUTHORIZED: Error = Error::Internal("client not authorized yet");
40const CLOSED_RECEIVER_ERROR: Error = Error::Internal("receiver already closed");
41const INVALID_RESPONSE_ERROR: Error = Error::Internal("receive invalid response");
42const NO_EXTRA: Error = Error::Internal("invalid tdlib response type, not have `extra` field");
43
44#[derive(Debug, Clone, PartialEq)]
46pub enum ClientState {
47 Opened,
49 Closed,
51 Authorizing,
53}
54
55#[derive(Debug, Clone)]
56pub struct ConsoleClientStateHandler;
57
58#[async_trait]
59impl ClientAuthStateHandler for ConsoleClientStateHandler {
60 async fn handle_wait_code(&self, _wait_code: &AuthorizationStateWaitCode) -> String {
61 println!("waiting for auth code");
62 utils::wait_input_sync()
63 }
64
65 async fn handle_encryption_key(
66 &self,
67 _wait_encryption_key: &AuthorizationStateWaitEncryptionKey,
68 ) -> String {
69 println!("waiting for encryption key");
70 utils::wait_input_sync()
71 }
72
73 async fn handle_wait_password(
74 &self,
75 _wait_password: &AuthorizationStateWaitPassword,
76 ) -> String {
77 println!("waiting for password");
78 utils::wait_input_sync()
79 }
80
81 async fn handle_wait_client_identifier(
82 &self,
83 _: &AuthorizationStateWaitPhoneNumber,
84 ) -> ClientIdentifier {
85 loop {
86 println!("ConsoleClientStateHandler: choose one of phone number (p) or bot token (b)");
87 let inp = utils::wait_input_sync();
88 match inp.to_lowercase().trim() {
89 "b" => {
90 println!("enter bot token");
91 return ClientIdentifier::BotToken(utils::wait_input_sync());
92 }
93 "p" => {
94 println!("ConsoleClientStateHandler: enter phone number");
95 return ClientIdentifier::PhoneNumber(utils::wait_input_sync());
96 }
97 _ => {
98 continue;
100 }
101 }
102 }
103 }
104
105 async fn handle_wait_registration(
106 &self,
107 _wait_registration: &AuthorizationStateWaitRegistration,
108 ) -> (String, String) {
109 loop {
110 println!("waiting for first_name and second_name separated by comma");
111 let inp: String = utils::wait_input_sync();
112 if let Some((f, l)) = utils::split_string(inp, ',') {
113 return (f, l);
114 }
115 }
116 }
117}
118
119#[derive(Debug, Clone)]
120pub struct ConsoleClientStateHandlerIdentified(ClientIdentifier);
121
122impl ConsoleClientStateHandlerIdentified {
123 pub fn new(ident: ClientIdentifier) -> Self {
124 Self(ident)
125 }
126}
127
128#[async_trait]
129impl ClientAuthStateHandler for ConsoleClientStateHandlerIdentified {
130 async fn handle_wait_code(&self, _wait_code: &AuthorizationStateWaitCode) -> String {
131 println!("waiting for auth code");
132 utils::wait_input_sync()
133 }
134
135 async fn handle_encryption_key(
136 &self,
137 _wait_encryption_key: &AuthorizationStateWaitEncryptionKey,
138 ) -> String {
139 println!("waiting for encryption key");
140 utils::wait_input_sync()
141 }
142
143 async fn handle_wait_password(
144 &self,
145 _wait_password: &AuthorizationStateWaitPassword,
146 ) -> String {
147 println!("waiting for password");
148 utils::wait_input_sync()
149 }
150
151 async fn handle_wait_client_identifier(
152 &self,
153 _: &AuthorizationStateWaitPhoneNumber,
154 ) -> ClientIdentifier {
155 self.0.clone()
156 }
157
158 async fn handle_wait_registration(
159 &self,
160 _wait_registration: &AuthorizationStateWaitRegistration,
161 ) -> (String, String) {
162 loop {
163 println!("waiting for first_name and second_name separated by comma");
164 let inp: String = utils::wait_input_sync();
165 if let Some((f, l)) = utils::split_string(inp, ',') {
166 return (f, l);
167 }
168 }
169 }
170}
171
172#[derive(Clone, Debug)]
175pub struct Client<S>
176where
177 S: TdLibClient + Clone,
178{
179 tdlib_client: S,
180 client_id: Option<i32>,
181 is_started: bool,
182 updates_sender: Option<mpsc::Sender<Box<Update>>>,
183 tdlib_parameters: TdlibParameters,
184 auth_state_channel_size: Option<usize>,
185 auth_handler: Box<dyn ClientAuthStateHandler>,
186}
187
188impl<S> Client<S>
189where
190 S: TdLibClient + Clone,
191{
192 pub(crate) fn get_auth_state_channel_size(&self) -> Option<usize> {
193 self.auth_state_channel_size
194 }
195
196 pub(crate) fn tdlib_parameters(&self) -> &TdlibParameters {
197 &self.tdlib_parameters
198 }
199
200 pub(crate) fn get_auth_handler(&self) -> Box<dyn ClientAuthStateHandler> {
201 dyn_clone::clone_box(&*self.auth_handler)
202 }
203
204 pub fn get_tdlib_client(&self) -> S {
205 self.tdlib_client.clone()
206 }
207
208 pub(crate) fn get_client_id(&self) -> Option<i32> {
209 self.client_id
210 }
211
212 pub(crate) fn take_client_id(&mut self) -> Result<i32> {
213 match self.client_id.take() {
214 Some(client_id) => Ok(client_id),
215 None => Err(CLIENT_NOT_AUTHORIZED),
216 }
217 }
218
219 pub(crate) fn set_client_id(&mut self, client_id: i32) -> Result<()> {
220 match self.client_id {
221 Some(_) => Err(Error::BadRequest("client already authorized")),
222 None => {
223 self.client_id = Some(client_id);
224 self.is_started = true;
225 Ok(())
226 }
227 }
228 }
229
230 pub(crate) fn updates_sender(&self) -> &Option<mpsc::Sender<Box<Update>>> {
231 &self.updates_sender
232 }
233}
234
235#[derive(Debug)]
236pub struct ClientBuilder<R, A>
237where
238 R: TdLibClient + Clone,
239 A: ClientAuthStateHandler + Clone + 'static,
240{
241 updates_sender: Option<mpsc::Sender<Box<Update>>>,
242 tdlib_parameters: Option<TdlibParameters>,
243 tdlib_client: R,
244 auth_state_channel_size: Option<usize>,
245 auth_handler: A,
246}
247
248impl Default for ClientBuilder<TdJson, ConsoleClientStateHandler> {
249 fn default() -> Self {
250 Self {
251 updates_sender: None,
252 tdlib_parameters: None,
253 auth_state_channel_size: None,
254 tdlib_client: TdJson::new(),
255 auth_handler: ConsoleClientStateHandler,
256 }
257 }
258}
259
260impl<R, A> ClientBuilder<R, A>
261where
262 R: TdLibClient + Clone,
263 A: ClientAuthStateHandler + Clone,
264{
265 pub fn with_updates_sender(mut self, updates_sender: mpsc::Sender<Box<Update>>) -> Self {
268 self.updates_sender = Some(updates_sender);
269 self
270 }
271
272 pub fn with_auth_state_channel(mut self, channel_size: usize) -> Self {
276 self.auth_state_channel_size = Some(channel_size);
277 self
278 }
279
280 pub fn with_tdlib_parameters(mut self, tdlib_parameters: TdlibParameters) -> Self {
282 self.tdlib_parameters = Some(tdlib_parameters);
283 self
284 }
285
286 pub fn with_client_auth_state_handler<NA: ClientAuthStateHandler + Clone>(
288 self,
289 auth_handler: NA,
290 ) -> ClientBuilder<R, NA> {
291 ClientBuilder {
292 auth_handler,
293 tdlib_client: self.tdlib_client,
294 updates_sender: self.updates_sender,
295 tdlib_parameters: self.tdlib_parameters,
296 auth_state_channel_size: self.auth_state_channel_size,
297 }
298 }
299
300 #[doc(hidden)]
301 pub fn with_tdlib_client<T: TdLibClient + Clone>(self, tdlib_client: T) -> ClientBuilder<T, A> {
302 ClientBuilder {
303 tdlib_client,
304 updates_sender: self.updates_sender,
305 tdlib_parameters: self.tdlib_parameters,
306 auth_state_channel_size: self.auth_state_channel_size,
307 auth_handler: self.auth_handler,
308 }
309 }
310
311 pub fn build(self) -> Result<Client<R>> {
312 if self.tdlib_parameters.is_none() {
313 return Err(Error::BadRequest("tdlib_parameters not set"));
314 };
315
316 let client = Client::new(
317 self.tdlib_client,
318 self.auth_handler,
319 self.updates_sender,
320 self.tdlib_parameters.unwrap(),
321 self.auth_state_channel_size,
322 );
323 Ok(client)
324 }
325}
326
327impl Client<TdJson> {
328 pub fn builder() -> ClientBuilder<TdJson, ConsoleClientStateHandler> {
329 ClientBuilder::default()
330 }
331}
332impl<R> Client<R>
335where
336 R: TdLibClient + Clone,
337{
338 #[doc(hidden)]
339 pub fn new<A: ClientAuthStateHandler + 'static>(
340 tdlib_client: R,
341 auth_handler: A,
342 updates_sender: Option<mpsc::Sender<Box<Update>>>,
343 tdlib_parameters: TdlibParameters,
344 auth_state_channel_size: Option<usize>,
345 ) -> Self {
346 Self {
347 tdlib_client,
348 updates_sender,
349 tdlib_parameters,
350 auth_handler: Box::new(auth_handler),
351 auth_state_channel_size,
352 is_started: false,
353 client_id: None,
354 }
355 }
356
357 pub fn set_updates_sender(&mut self, updates_sender: mpsc::Sender<Box<Update>>) -> Result<()> {
358 match self.is_started {
359 true => Err(Error::BadRequest(
360 "can't set updates sender when client already started",
361 )),
362 false => {
363 self.updates_sender = Some(updates_sender);
364 Ok(())
365 }
366 }
367 }
368
369 pub async fn stop(&self) -> Result<Ok> {
371 self.close(Close::builder().build()).await
372 }
373
374 pub(crate) async fn reload(&mut self, client_id: i32) -> Result<i32> {
375 self.stop().await?;
376 Ok(self.client_id.replace(client_id).unwrap_or_default())
377 }
378
379 async fn make_request<T: RFunction, P: AsRef<T>, Q: DeserializeOwned>(
380 &self,
381 param: P,
382 ) -> Result<Q> {
383 let extra = param.as_ref().extra().ok_or(NO_EXTRA)?;
384 let signal = OBSERVER.subscribe(extra);
385 log::trace!("sending request: {:?}", param.as_ref());
386 self.tdlib_client.send(
387 self.get_client_id().ok_or(CLIENT_NOT_AUTHORIZED)?,
388 param.as_ref(),
389 )?;
390 let received = signal.await;
391 OBSERVER.unsubscribe(extra);
392 match received {
393 Err(_) => Err(CLOSED_RECEIVER_ERROR),
394 Ok(v) => {
395 if error_received(&v) {
396 match serde_json::from_value::<TDLibError>(v) {
397 Ok(v) => Err(Error::TDLibError(v)),
398 Err(e) => {
399 log::error!("cannot deserialize error response: {:?}", e);
400 Err(INVALID_RESPONSE_ERROR)
401 }
402 }
403 } else {
404 match serde_json::from_value::<Q>(v) {
405 Ok(v) => Ok(v),
406 Err(e) => {
407 log::error!("response serialization error: {:?}", e);
408 Err(INVALID_RESPONSE_ERROR)
409 }
410 }
411 }
412 }
413 }
414 }
415}
416
417fn error_received(value: &serde_json::Value) -> bool {
418 value.get("@type") == Some(&serde_json::Value::String("error".to_string()))
419}