use super::api::{EventPayload, GetAddressResponse, TEERequest, TEEResponse};
use super::SP1_TEE_VERSION;
use alloy_primitives::Address;
use eventsource_stream::{EventStreamError, Eventsource};
use futures::stream::StreamExt;
use reqwest::{Client as HttpClient, Error as HttpError};
#[derive(Debug, thiserror::Error)]
pub enum ClientError {
#[error("Http Error: {0}")]
Http(#[from] HttpError),
#[error("Event Error: {0}")]
Event(#[from] EventStreamError<HttpError>),
#[error("Failed to parse response: {0}")]
Parse(#[from] bincode::Error),
#[error("Failed to decode event: {0}")]
Decode(#[from] hex::FromHexError),
#[error("Error received from server: {0}")]
ServerError(String),
#[error("No response received")]
NoResponse,
}
pub struct Client {
client: HttpClient,
url: String,
}
impl Default for Client {
fn default() -> Self {
Self::new(crate::network::DEFAULT_TEE_SERVER_URL)
}
}
impl Client {
#[must_use]
pub fn new(url: &str) -> Self {
Self { client: HttpClient::new(), url: url.to_string() }
}
pub async fn execute(&self, request: TEERequest) -> Result<TEEResponse, ClientError> {
let payload: EventPayload = self
.client
.post(format!("{}/execute", self.url))
.header("X-SP1-Tee-Version", SP1_TEE_VERSION)
.body(bincode::serialize(&request)?)
.send()
.await?
.bytes_stream()
.eventsource()
.map(|event| match event {
Ok(event) => {
let decoded = hex::decode(&event.data)?;
Ok(bincode::deserialize(&decoded)?)
}
Err(e) => Err(ClientError::Event(e)),
})
.next()
.await
.ok_or(ClientError::NoResponse)??;
match payload {
EventPayload::Success(response) => Ok(response),
EventPayload::Error(error) => Err(ClientError::ServerError(error)),
}
}
pub async fn get_address(&self) -> Result<Address, ClientError> {
let response = self
.client
.get(format!("{}/address", self.url))
.header("X-SP1-Tee-Version", SP1_TEE_VERSION)
.send()
.await?
.json::<GetAddressResponse>()
.await?;
Ok(response.address)
}
pub async fn get_signers(&self) -> Result<Vec<Address>, ClientError> {
let response = self
.client
.get(format!("{}/signers", self.url))
.header("X-SP1-Tee-Version", SP1_TEE_VERSION)
.send()
.await?
.bytes()
.await?;
bincode::deserialize(&response).map_err(ClientError::Parse)
}
}