* refactor: Config 采用 arc_swap 而非锁 * refactor: 改进 config 的检查,及其他一些细微优化 * refactor: 不再拆分 lib.rs 和 main.rs
86 lines
2.8 KiB
Rust
86 lines
2.8 KiB
Rust
use std::sync::Arc;
|
||
|
||
use anyhow::Result;
|
||
use reqwest::{header, Method};
|
||
|
||
use crate::bilibili::Credential;
|
||
use crate::config::CONFIG;
|
||
|
||
// 一个对 reqwest::Client 的简单封装,用于 Bilibili 请求
|
||
pub struct Client(reqwest::Client);
|
||
|
||
impl Client {
|
||
pub fn new() -> Self {
|
||
// 正常访问 api 所必须的 header,作为默认 header 添加到每个请求中
|
||
let mut headers = header::HeaderMap::new();
|
||
headers.insert(
|
||
header::USER_AGENT,
|
||
header::HeaderValue::from_static(
|
||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
|
||
),
|
||
);
|
||
headers.insert(
|
||
header::REFERER,
|
||
header::HeaderValue::from_static("https://www.bilibili.com"),
|
||
);
|
||
Self(
|
||
reqwest::Client::builder()
|
||
.default_headers(headers)
|
||
.gzip(true)
|
||
.build()
|
||
.unwrap(),
|
||
)
|
||
}
|
||
|
||
// a wrapper of reqwest::Client::request to add credential to the request
|
||
pub fn request(&self, method: Method, url: &str, credential: Option<&Credential>) -> reqwest::RequestBuilder {
|
||
let mut req = self.0.request(method, url);
|
||
// 如果有 credential,会将其转换成 cookie 添加到请求的 header 中
|
||
if let Some(credential) = credential {
|
||
req = req
|
||
.header(header::COOKIE, format!("SESSDATA={}", credential.sessdata))
|
||
.header(header::COOKIE, format!("bili_jct={}", credential.bili_jct))
|
||
.header(header::COOKIE, format!("buvid3={}", credential.buvid3))
|
||
.header(header::COOKIE, format!("DedeUserID={}", credential.dedeuserid))
|
||
.header(header::COOKIE, format!("ac_time_value={}", credential.ac_time_value));
|
||
}
|
||
req
|
||
}
|
||
}
|
||
|
||
// clippy 建议实现 Default trait
|
||
impl Default for Client {
|
||
fn default() -> Self {
|
||
Self::new()
|
||
}
|
||
}
|
||
|
||
pub struct BiliClient {
|
||
client: Client,
|
||
}
|
||
|
||
impl BiliClient {
|
||
pub fn new() -> Self {
|
||
let client = Client::new();
|
||
Self { client }
|
||
}
|
||
|
||
pub fn request(&self, method: Method, url: &str) -> reqwest::RequestBuilder {
|
||
let credential = CONFIG.credential.load();
|
||
self.client.request(method, url, credential.as_deref())
|
||
}
|
||
|
||
pub async fn check_refresh(&self) -> Result<()> {
|
||
let credential = CONFIG.credential.load();
|
||
let Some(credential) = credential.as_deref() else {
|
||
return Ok(());
|
||
};
|
||
if !credential.need_refresh(&self.client).await? {
|
||
return Ok(());
|
||
}
|
||
let new_credential = credential.refresh(&self.client).await?;
|
||
CONFIG.credential.store(Some(Arc::new(new_credential)));
|
||
CONFIG.save()
|
||
}
|
||
}
|