Skip to content

Commit

Permalink
Request Handloooorrrr
Browse files Browse the repository at this point in the history
  • Loading branch information
0xIchigo committed Apr 19, 2024
1 parent 9bc79c7 commit f05b513
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ documentation = "https://docs.rs/helius-sdk"
readme = "README.md"

[dependencies]
reqwest = "0.12.3"
reqwest = { version = "0.12.3", features = ["json"] }
serde = "1.0.198"
serde_json = "1.0.116"
solana-sdk = "1.18.11"
Expand Down
15 changes: 14 additions & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
#![allow(dead_code)]
use std::sync::Arc;

use crate::config::Config;
use crate::error::Result;
use crate::rpc_client::RpcClient;
use crate::types::Cluster;

use reqwest::Client;

pub struct Helius {
pub config: Config,
pub client: Client,
pub rpc_client: Arc<RpcClient>,
}

impl Helius {
pub fn new(api_key: &str, cluster: Cluster) -> Result<Self> {
let config: Config = Config::new(api_key, cluster)?;
let client: Client = Client::new();
let rpc_client: RpcClient = Arc::new(RpcClient::new(Arc::new(client.clone()), config.clone()));

Ok(Helius { config, client })
Ok(Helius {
config,
client,
rpc_client,
})
}

/// Provides a thread-safe way to access RPC functionalities
pub fn rpc(&self) -> Arc<RpcClient> {
self.rpc_client.clone()
}
}
1 change: 1 addition & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::error::{HeliusError, Result};
use crate::types::{Cluster, HeliusEndpoints};

#[derive(Clone)]
pub struct Config {
pub api_key: String,
pub cluster: Cluster,
Expand Down
23 changes: 22 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use reqwest::{Error as ReqwestError, StatusCode};
use serde_json::Error as SerdeError;
use thiserror::Error;

#[derive(Debug, Error)]
Expand All @@ -13,15 +12,37 @@ pub enum HeliusError {
#[error("Invalid input: {0}")]
InvalidInput(String),

#[error("Network error: {0}")]
Network(ReqwestError),

#[error("Not found: {text}")]
NotFound { text: String },

#[error("Too many requests made to {path}")]
RateLimitExceeded { path: String },

#[error("Serialization / Deserialization error: {0}")]
SerdeJson(ReqwestError),

#[error("Unauthorized access to {path}: {text}")]
Unauthorized { path: String, text: String },

#[error("Unknown error has occurred: HTTP {code} - {text}")]
Unknown { code: StatusCode, text: String },
}

impl HeliusError {
pub fn from_response_status(status: StatusCode, path: String, text: String) -> Self {
match status {
StatusCode::BAD_REQUEST => HeliusError::BadRequest { path, text },
StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN => HeliusError::Unauthorized { path, text },
StatusCode::NOT_FOUND => HeliusError::NotFound { text },
StatusCode::INTERNAL_SERVER_ERROR => HeliusError::InternalError { code: status, text },
StatusCode::TOO_MANY_REQUESTS => HeliusError::RateLimitExceeded { path },
_ => HeliusError::Unknown { code: status, text },
}
}
}

// Handy type alias
pub type Result<T> = std::result::Result<T, HeliusError>;
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ pub mod das_api;
pub mod error;
pub mod factory;
pub mod mint_api;
pub mod rpc;
pub mod request_handler;
pub mod rpc_client;
pub mod types;
pub mod utils;
pub mod webhook;
Expand Down
48 changes: 48 additions & 0 deletions src/request_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::error::{HeliusError, Result};
use reqwest::{Client, Method, RequestBuilder, Response, StatusCode, Url};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::sync::Arc;

#[derive(Clone)]
pub struct RequestHandler {
pub http_client: Arc<Client>,
}

impl RequestHandler {
pub fn new(client: Arc<Client>) -> Result<Self> {
Ok(Self { http_client: client })
}

async fn send_request(&self, request_builder: RequestBuilder) -> Result<Response> {
let response: Response = request_builder.send().await.map_err(|e| HeliusError::Network(e))?;
Ok(response)
}

pub async fn send<R, T>(&self, method: Method, url: Url, body: Option<&R>) -> Result<T>
where
R: Serialize + ?Sized + Send + Sync + Debug,
T: for<'de> Deserialize<'de> + Default,
{
let mut request_builder: RequestBuilder = self.http_client.request(method, url.clone());

if let Some(body) = body {
request_builder = request_builder.json(body);
}

let response: Response = self.send_request(request_builder).await?;
let path: String = url.path().to_string();
self.handle_response(path, response).await
}

async fn handle_response<T: for<'de> Deserialize<'de>>(&self, path: String, response: Response) -> Result<T> {
let status: StatusCode = response.status();

if status == StatusCode::OK || status == StatusCode::CREATED {
response.json::<T>().await.map_err(HeliusError::SerdeJson)
} else {
let error_text: String = response.text().await.unwrap_or_default();
Err(HeliusError::from_response_status(status, path, error_text))
}
}
}
1 change: 0 additions & 1 deletion src/rpc.rs

This file was deleted.

19 changes: 19 additions & 0 deletions src/rpc_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use std::sync::Arc;

use crate::config::Config;
use crate::error::Result;
use crate::request_handler::RequestHandler;

use reqwest::Client;

pub struct RpcClient {
pub handler: RequestHandler,
pub config: Arc<Config>,
}

impl RpcClient {
pub fn new(client: Arc<Client>, config: Arc<Config>) -> Result<Self> {
let handler: RequestHandler = RequestHandler::new(client)?;
Ok(RpcClient { handler, config })
}
}

0 comments on commit f05b513

Please sign in to comment.