Skip to main content

grammers_client/
utils.rs

1// Copyright 2020 - developers of the `grammers` project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::sync::atomic::{AtomicI64, Ordering};
10use std::thread;
11use std::time::SystemTime;
12
13use chrono::{DateTime, Utc};
14use grammers_tl_types as tl;
15
16// This atomic isn't for anything critical, just to generate unique IDs without locks.
17// The worst that can happen if the load and store orderings are wrong is that the IDs
18// are not actually unique which could confuse some of the API results.
19static LAST_ID: AtomicI64 = AtomicI64::new(0);
20
21/// Generate a "random" ID suitable for sending messages or media.
22pub(crate) fn generate_random_id() -> i64 {
23    while LAST_ID.load(Ordering::SeqCst) == 0 {
24        let now = SystemTime::now()
25            .duration_since(SystemTime::UNIX_EPOCH)
26            .expect("system time is before epoch")
27            .as_nanos() as i64;
28
29        if LAST_ID
30            .compare_exchange(0, now, Ordering::SeqCst, Ordering::SeqCst)
31            .is_err()
32        {
33            thread::yield_now();
34        }
35    }
36
37    LAST_ID.fetch_add(1, Ordering::SeqCst)
38}
39
40pub(crate) fn generate_random_ids(n: usize) -> Vec<i64> {
41    (0..n).map(|_| generate_random_id()).collect()
42}
43
44pub(crate) fn date(date: i32) -> DateTime<Utc> {
45    DateTime::<Utc>::from_timestamp(date as i64, 0).expect("date out of range")
46}
47
48pub(crate) fn extract_password_parameters(
49    current_algo: &tl::enums::PasswordKdfAlgo,
50) -> (&Vec<u8>, &Vec<u8>, &Vec<u8>, &i32) {
51    let tl::types::PasswordKdfAlgoSha256Sha256Pbkdf2Hmacsha512iter100000Sha256ModPow {
52        salt1,
53        salt2,
54        p,
55        g,
56    } = match current_algo {
57        tl::enums::PasswordKdfAlgo::Unknown => panic!(
58            "Unknown KDF (most likely, the client is outdated and does not support the specified KDF algorithm)"
59        ),
60        tl::enums::PasswordKdfAlgo::Sha256Sha256Pbkdf2Hmacsha512iter100000Sha256ModPow(alg) => alg,
61    };
62    (salt1, salt2, p, g)
63}
64
65pub(crate) fn peer_from_message(message: &tl::enums::Message) -> Option<tl::enums::Peer> {
66    match &message {
67        tl::enums::Message::Empty(message) => message.peer_id.clone(),
68        tl::enums::Message::Message(message) => Some(message.peer_id.clone()),
69        tl::enums::Message::Service(message) => Some(message.peer_id.clone()),
70    }
71}