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!(
27            "{READING_ADDRESS}?id={id}&lang=en&token={}",
28            reading_token(id)
29        ))
30    }
31}
32
33/// Names the address one public tweet is read from.
34///
35/// It is the address that answers an embedded tweet on somebody else's page, which is why it
36/// answers at all without an account, a cookie, or anything anybody has to be given.
37pub const READING_ADDRESS: &str = "https://cdn.syndication.twimg.com/tweet-result";
38
39/// States the token one tweet is read with.
40///
41/// The address answers with nothing unless it is asked with a token. What the token *is* does not
42/// decide the answer — only that there is one — so this derives one from the identity itself: the
43/// request for a tweet stays a function of which tweet it is, and there is no shared secret and
44/// nothing to keep in step with anybody.
45#[must_use]
46pub fn reading_token(id: &str) -> String {
47    const DIGITS: &[u8; 36] = b"0123456789abcdefghijklmnopqrstuvwxyz";
48    let mut remaining = id.bytes().fold(0_u128, |carried, digit| {
49        carried
50            .saturating_mul(10)
51            .saturating_add(u128::from(digit.wrapping_sub(b'0')))
52    });
53    let mut stated = Vec::new();
54    while remaining > 0 {
55        stated.push(DIGITS[usize::try_from(remaining % 36).unwrap_or_default()]);
56        remaining /= 36;
57    }
58    if stated.is_empty() {
59        stated.push(DIGITS[0]);
60    }
61    stated.reverse();
62    String::from_utf8(stated).unwrap_or_default()
63}