use super::{extract::Update, responses::LongPollSession, Error, Result};
use serde::Serialize;
use serde_json::Value;
pub struct RequestBuilder {
client: reqwest::Client,
access_token: String,
group_id: u32,
}
pub const VK: &'static str = "https://api.vk.com/method";
pub const VERSION: &'static str = "5.199";
macro_rules! request {
($fn1:ident) => {
pub async fn $fn1<T: Serialize + Send, A: Serialize + Send + Sized>(
&self,
url: &str,
method: &str,
query: A,
body: T,
) -> std::result::Result<Value, reqwest::Error> {
let response = self
.client
.post(&if method.is_empty() {
format!("{}?v={}", url, VERSION)
} else {
format!("{}/{}?v={}", url, method, VERSION)
})
.query(&query)
.bearer_auth(&self.access_token)
.json(&body)
.send()
.await?;
let json: Value = response.json().await?;
Ok(json)
}
};
}
impl RequestBuilder {
pub fn new(access_token: &str, group_id: u32) -> Self {
RequestBuilder {
client: reqwest::Client::new(),
access_token: access_token.to_string(),
group_id,
}
}
pub async fn build_long_poll_request(&self) -> Result<Update> {
let response = self
.post(
VK,
"groups.getLongPollServer",
&[("group_id", self.group_id)],
{},
)
.await
.map_err(|e| Error::Reqwest(e))?;
let parsed_response =
crate::parse_response!(response, LongPollSession).map_err(|e| Error::SerdeJson(e))?;
let response = self
.post(
&parsed_response.server,
"",
&[
("act", String::from("a_check")),
("key", parsed_response.key),
("ts", parsed_response.ts),
("wait", String::from("25")),
],
{},
)
.await
.map_err(|e| Error::Reqwest(e))?;
let parsed_response =
crate::parse_response!(response, Update).map_err(|e| Error::SerdeJson(e))?;
match parsed_response.failed {
Some(1) => Err(Error::EventsOutdated {
new_ts: parsed_response.ts.unwrap(),
}),
Some(2) => Err(Error::KeyExpired),
Some(3) => Err(Error::InformationLost),
_ => Ok(parsed_response),
}
}
request!(post);
request!(get);
}