use common::message::{Request, Response}; use sdk::vanadium_client::{VAppClient, VAppExecutionError}; use sdk::comm::SendMessageError; pub use sdk::{transport, vanadium_client}; #[derive(Debug)] pub enum AtprotoAppClientError { VAppExecutionError(VAppExecutionError), SendMessageError(SendMessageError), InvalidResponse(&'static str), GenericError(&'static str), } impl From for AtprotoAppClientError { fn from(e: VAppExecutionError) -> Self { Self::VAppExecutionError(e) } } impl From for AtprotoAppClientError { fn from(e: SendMessageError) -> Self { Self::SendMessageError(e) } } impl From<&'static str> for AtprotoAppClientError { fn from(e: &'static str) -> Self { Self::GenericError(e) } } impl std::fmt::Display for AtprotoAppClientError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { AtprotoAppClientError::VAppExecutionError(e) => write!(f, "VAppExecutionError: {}", e), AtprotoAppClientError::SendMessageError(e) => write!(f, "SendMessageError: {}", e), AtprotoAppClientError::InvalidResponse(e) => write!(f, "InvalidResponse: {}", e), AtprotoAppClientError::GenericError(e) => write!(f, "GenericError: {}", e), } } } impl std::error::Error for AtprotoAppClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { AtprotoAppClientError::VAppExecutionError(e) => Some(e), AtprotoAppClientError::SendMessageError(e) => Some(e), AtprotoAppClientError::InvalidResponse(_) => None, AtprotoAppClientError::GenericError(_) => None, } } } pub struct AtprotoAppClient { app_client: Box, } impl<'a> AtprotoAppClient { pub fn new(app_client: Box) -> Self { Self { app_client } } async fn send_message(&mut self, out: &[u8]) -> Result, AtprotoAppClientError> { sdk::comm::send_message(&mut self.app_client, out) .await .map_err(AtprotoAppClientError::from) } async fn parse_response(response_raw: &'a [u8]) -> Result { let resp: Response = postcard::from_bytes(response_raw) .map_err(|_| AtprotoAppClientError::GenericError("Failed to parse response"))?; Ok(resp) } pub async fn get_did_key( &mut self, index: u32, display: bool, ) -> Result, AtprotoAppClientError> { let msg = postcard::to_allocvec(&Request::GetDidKey { index, display }) .map_err(|_| AtprotoAppClientError::GenericError("Failed to serialize Exit request"))?; let response_raw = self.send_message(&msg).await?; match Self::parse_response(&response_raw).await? { Response::DidKey(key) => Ok(key), _ => Err(AtprotoAppClientError::InvalidResponse("Invalid response")), } } pub async fn exit(&mut self) -> Result { let msg = postcard::to_allocvec(&Request::Exit) .map_err(|_| AtprotoAppClientError::GenericError("Failed to serialize Exit request"))?; let response_raw = self.send_message(&msg).await?; match Self::parse_response(&response_raw).await { Ok(_) => Err(AtprotoAppClientError::InvalidResponse( "Exit message shouldn't return!", )), Err(e) => match e { AtprotoAppClientError::VAppExecutionError(VAppExecutionError::AppExited( status, )) => Ok(status), e => { println!("Unexpected error on exit: {:?}", e); Err(AtprotoAppClientError::InvalidResponse( "Unexpected error on exit", )) } }, } } }