use anyhow::{anyhow, Result};
use async_tungstenite::tungstenite::{client::IntoClientRequest, http::HeaderValue, Message};
use futures::StreamExt;
use graphql_client::{QueryBody, Response};
use graphql_ws_client::{graphql::GraphQLClient, AsyncWebsocketClient, GraphQLClientClientBuilder};
use serde::{de::DeserializeOwned, Serialize};
pub async fn query<Q, R>(executor_url: String, cap_token: String, query: QueryBody<Q>) -> Result<R>
where
Q: Serialize,
R: DeserializeOwned,
{
let response_body: Response<R> = reqwest::Client::new()
.post(executor_url)
.header("authorization", cap_token)
.json(&query)
.send()
.await?
.json()
.await?;
let response_data = response_body
.data
.ok_or_else(|| anyhow!("No data in response! Errors: {:?}", response_body.errors))?;
Ok(response_data)
}
pub async fn query_raw<Q, R>(
executor_url: String,
cap_token: String,
query: QueryBody<Q>,
) -> Result<Response<R>>
where
Q: Serialize,
R: DeserializeOwned,
{
Ok(reqwest::Client::new()
.post(executor_url)
.header("authorization", cap_token)
.json(&query)
.send()
.await?
.json()
.await?)
}
struct TokioSpawner(tokio::runtime::Handle);
impl TokioSpawner {
pub fn new(handle: tokio::runtime::Handle) -> Self {
TokioSpawner(handle)
}
pub fn current() -> Self {
TokioSpawner::new(tokio::runtime::Handle::current())
}
}
impl futures::task::Spawn for TokioSpawner {
fn spawn_obj(
&self,
obj: futures::task::FutureObj<'static, ()>,
) -> Result<(), futures::task::SpawnError> {
self.0.spawn(obj);
Ok(())
}
}
pub async fn create_websocket_client(
executor_url: String,
cap_token: String,
) -> Result<AsyncWebsocketClient<GraphQLClient, Message>> {
let url = executor_url.replace("http", "ws");
let mut request = url.into_client_request().unwrap();
request.headers_mut().insert(
"Sec-WebSocket-Protocol",
HeaderValue::from_str("graphql-transport-ws").unwrap(),
);
request
.headers_mut()
.insert("authorization", HeaderValue::from_str(&cap_token).unwrap());
let (connection, _) = async_tungstenite::tokio::connect_async(request).await?;
let (sink, stream) = connection.split();
let client = GraphQLClientClientBuilder::new()
.build(stream, sink, TokioSpawner::current())
.await
.unwrap();
Ok(client)
}