Skip to main content

rsynko_x/
request.rs

1use crate::XSorts;
2use alux_ext::ext;
3use ambassador::delegatable_trait;
4
5/// Provides the carrier and constructor for exactly the request that asks about one tweet.
6#[delegatable_trait]
7pub trait XRequestAlg: XSorts {
8    /// Defines the request asking one address what it holds.
9    fn tweet_request(&self, address: impl Into<String>) -> Self::Request;
10}
11
12/// Specifies what one request states about itself.
13pub trait XRequestViewAlg: XSorts {
14    /// Observes the address the request asks.
15    fn request_address<'a>(&self, request: &'a Self::Request) -> &'a str;
16}
17
18/// Derives the request that asks what one tweet carries.
19#[ext(name = XRequestExt)]
20pub impl<This> This
21where
22    This: XRequestAlg,
23{
24    /// States the request asking what the tweet one identity names carries.
25    fn status_request(&self, id: &str) -> This::Request {
26        self.tweet_request(format!("{READING_ADDRESS}?id={id}&lang=en&token={}", reading_token(id)))
27    }
28}
29
30/// Names the address one public tweet is read from.
31///
32/// It is the address that answers an embedded tweet on somebody else's page, which is why it
33/// answers at all without an account, a cookie, or anything anybody has to be given.
34pub const READING_ADDRESS: &str = "https://cdn.syndication.twimg.com/tweet-result";
35
36/// States the token one tweet is read with.
37///
38/// The address answers with nothing unless it is asked with a token. What the token *is* does not
39/// decide the answer — only that there is one — so this derives one from the identity itself: the
40/// request for a tweet stays a function of which tweet it is, and there is no shared secret and
41/// nothing to keep in step with anybody.
42#[must_use]
43pub fn reading_token(id: &str) -> String {
44    const DIGITS: &[u8; 36] = b"0123456789abcdefghijklmnopqrstuvwxyz";
45    let mut remaining = id
46        .bytes()
47        .fold(0_u128, |carried, digit| carried.saturating_mul(10).saturating_add(u128::from(digit.wrapping_sub(b'0'))));
48    let mut stated = Vec::new();
49    while remaining > 0 {
50        stated.push(DIGITS[usize::try_from(remaining % 36).unwrap_or_default()]);
51        remaining /= 36;
52    }
53    if stated.is_empty() {
54        stated.push(DIGITS[0]);
55    }
56    stated.reverse();
57    String::from_utf8(stated).unwrap_or_default()
58}