ctx_/
user.rs

1use std::fmt::Debug;
2
3use aok::{OK, Result};
4use xkv::{
5  R,
6  fred::interfaces::{KeysInterface, SortedSetsInterface},
7};
8use xbin::concat;
9use cookie_b::Browser;
10
11use crate::{Ctx, Extract};
12
13pub struct User {
14  pub id: u64,
15  pub bin: Box<[u8]>,
16}
17
18impl User {
19  pub fn new(id: u64) -> Self {
20    Self {
21      id,
22      bin: intbin::u64_bin(id),
23    }
24  }
25}
26
27impl Debug for User {
28  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29    f.write_str(format!("User:{}", self.id).as_str())
30  }
31}
32
33/// https://developer.chrome.com/blog/cookie-max-age-expires?hl=zh-cn
34pub const COOKIE_EXPIRE: i64 = 86400 * 400;
35
36impl Extract for User {
37  async fn from_ctx(ctx: &Ctx) -> Result<Self> {
38    let bin: Box<[u8]>;
39    let id;
40
41    let req = &ctx.req;
42
43    #[allow(clippy::never_loop)]
44    loop {
45      if let Some(uid) = req.headers.get("content-type")
46        && let Ok(uid) = uid.to_str()
47        && uid != "#"
48        && let Ok(uid_bin) = ub64::b64d(uid)
49        && let Some(browser) = req.extensions.get::<Browser>()
50      {
51        /*
52          uid : ts
53
54          ts 按上次登录时间时间排序
55          ts 小于 0 为退出登录
56        */
57        let key = concat([b"bU:", &browser.bin[..]]);
58
59        let score: Option<i64> = R.zscore(&key[..], &uid_bin[..]).await?;
60
61        if let Some(score) = score
62          && score > 0
63        {
64          bin = uid_bin.into();
65          id = intbin::bin_u64(&bin);
66          if browser.renew {
67            tokio::spawn(async move {
68              R!(expire & key[..], COOKIE_EXPIRE, None);
69              OK
70            });
71          }
72          break;
73        }
74      }
75      bin = Box::new([]);
76      id = 0;
77      break;
78    }
79
80    Ok(Self { id, bin })
81  }
82}