use std::backtrace::Backtrace; use nyquest::{AsyncClient, Body, Request, header::USER_AGENT}; mod model; use model::{GetResponse, GetUserId}; use serde::Serialize; pub struct QRCode<'a> { pub qrcode_content: &'a str, } #[derive(Debug, snafu::Snafu, Serialize)] pub enum QRLoginError { #[snafu(display("QRCode expired [10mins]"))] QRCodeExpired10, #[snafu(display("QRCode expired [30mins]"))] QRCodeExpired30, #[snafu(display("Bad signature!"))] BadSingature, #[snafu(display("unknown error: {error_kind}"))] Unknown { error_kind: i64 }, #[snafu(context(false))] #[snafu(display("request error: {source}"))] NyquestError { #[serde(skip)] source: nyquest::Error, #[serde(skip)] backtrace: Backtrace, }, #[snafu(context(false))] JSONError { #[serde(skip)] source: serde_json::error::Error, #[serde(skip)] backtrace: Backtrace, }, } impl QRCode<'_> { pub async fn login(self, client: &AsyncClient) -> Result { let qr_code = &self.qrcode_content.as_bytes()[self.qrcode_content.len() - 64..]; let qr_code = String::from_utf8_lossy(qr_code); let req = Request::post("http://ai.sys-allnet.cn/wc_aime/api/get_data") .with_body(Body::json(&GetUserId::new(qr_code))?) .with_header(USER_AGENT, "WC_AIME_LIB"); let resp = client.request(req).await?; let resp: GetResponse = resp.json().await?; let user_id = resp.user_id; match resp.error_id { 0 => return Ok(user_id), 2 => Err(QRLoginError::QRCodeExpired10), 1 => Err(QRLoginError::QRCodeExpired30), 50 => Err(QRLoginError::BadSingature), error_kind => Err(QRLoginError::Unknown { error_kind }), } } }