qbittorrent_web_api/qbittorrent-web-api-gen/src/skeleton.rs

105 lines
3.1 KiB
Rust

use quote::quote;
use crate::util;
pub const AUTH_IDENT: &str = "Authenticated";
pub fn auth_ident() -> proc_macro2::Ident {
util::to_ident(AUTH_IDENT)
}
pub fn generate_skeleton(ident: &syn::Ident) -> proc_macro2::TokenStream {
let auth = auth_ident();
quote! {
use reqwest::RequestBuilder;
use serde::Deserialize;
use thiserror::Error;
use super::#ident;
impl #ident {
/// Creates an authenticated client.
/// base_url is the url to the qbittorrent instance, i.e. http://localhost:8080
pub async fn login(
base_url: &str,
username: &str,
password: &str,
) -> Result<#auth> {
let client = reqwest::Client::new();
let form = reqwest::multipart::Form::new()
.text("username", username.to_string())
.text("password", password.to_string());
let auth_resp = client
.post(format!("{}/api/v2/auth/login", base_url))
.multipart(form)
.send()
.await?;
let cookie_header = match auth_resp.headers().get("set-cookie") {
Some(header) => header.to_str().unwrap(),
None => {
return Err(Error::InvalidUsernameOrPassword);
}
};
fn parse_cookie(input: &str) -> Result<&str> {
match input.split(';').next() {
Some(res) => Ok(res),
_ => Err(Error::AuthCookieParseError),
}
}
let auth_cookie = parse_cookie(cookie_header)?;
Ok(#auth {
client,
auth_cookie: auth_cookie.to_string(),
base_url: base_url.to_string(),
})
}
}
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Error)]
pub enum Error {
#[error("failed to parse auth cookie")]
AuthCookieParseError,
#[error("invalid username or password (failed to parse auth cookie)")]
InvalidUsernameOrPassword,
#[error("request error: {0}")]
HttpError(#[from] reqwest::Error),
}
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub struct #auth {
auth_cookie: String,
base_url: String,
client: reqwest::Client,
}
impl #auth {
fn authenticated_client(&self, url: &str) -> RequestBuilder {
let url = format!("{}{}", self.base_url, url);
let cookie = self.auth_cookie.clone();
self.client
.post(url)
.header("cookie", cookie)
}
pub async fn logout(self) -> Result<()> {
self.authenticated_client("/api/v2/auth/logout")
.send()
.await?;
Ok(())
}
}
}
}