wip
1pub use common::message::{PlcOperation, SignedPlcOperation};
2use common::message::{Request, Response};
3use sdk::vanadium_client::{VAppClient, VAppExecutionError};
4
5use sdk::comm::SendMessageError;
6
7pub use sdk::{transport, vanadium_client};
8
9#[derive(Debug)]
10pub enum AtprotoAppClientError {
11 VAppExecutionError(VAppExecutionError),
12 SendMessageError(SendMessageError),
13 InvalidResponse(&'static str),
14 GenericError(&'static str),
15}
16
17impl From<VAppExecutionError> for AtprotoAppClientError {
18 fn from(e: VAppExecutionError) -> Self {
19 Self::VAppExecutionError(e)
20 }
21}
22
23impl From<SendMessageError> for AtprotoAppClientError {
24 fn from(e: SendMessageError) -> Self {
25 Self::SendMessageError(e)
26 }
27}
28
29impl From<&'static str> for AtprotoAppClientError {
30 fn from(e: &'static str) -> Self {
31 Self::GenericError(e)
32 }
33}
34
35impl std::fmt::Display for AtprotoAppClientError {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 AtprotoAppClientError::VAppExecutionError(e) => write!(f, "VAppExecutionError: {}", e),
39 AtprotoAppClientError::SendMessageError(e) => write!(f, "SendMessageError: {}", e),
40 AtprotoAppClientError::InvalidResponse(e) => write!(f, "InvalidResponse: {}", e),
41 AtprotoAppClientError::GenericError(e) => write!(f, "GenericError: {}", e),
42 }
43 }
44}
45
46impl std::error::Error for AtprotoAppClientError {
47 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
48 match self {
49 AtprotoAppClientError::VAppExecutionError(e) => Some(e),
50 AtprotoAppClientError::SendMessageError(e) => Some(e),
51 AtprotoAppClientError::InvalidResponse(_) => None,
52 AtprotoAppClientError::GenericError(_) => None,
53 }
54 }
55}
56
57pub struct AtprotoAppClient {
58 app_client: Box<dyn VAppClient + Send + Sync>,
59}
60
61impl<'a> AtprotoAppClient {
62 pub fn new(app_client: Box<dyn VAppClient + Send + Sync>) -> Self {
63 Self { app_client }
64 }
65
66 async fn send_message(&mut self, out: &[u8]) -> Result<Vec<u8>, AtprotoAppClientError> {
67 sdk::comm::send_message(&mut self.app_client, out)
68 .await
69 .map_err(AtprotoAppClientError::from)
70 }
71
72 async fn parse_response(response_raw: &'a [u8]) -> Result<Response, AtprotoAppClientError> {
73 let resp: Response = postcard::from_bytes(response_raw)
74 .map_err(|_| AtprotoAppClientError::GenericError("Failed to parse response"))?;
75 Ok(resp)
76 }
77
78 pub async fn get_did_key(
79 &mut self,
80 index: u32,
81 display: bool,
82 ) -> Result<Vec<u8>, AtprotoAppClientError> {
83 let msg = postcard::to_allocvec(&Request::GetDidKey { index, display })
84 .map_err(|_| AtprotoAppClientError::GenericError("Failed to serialize Exit request"))?;
85
86 let response_raw = self.send_message(&msg).await?;
87 match Self::parse_response(&response_raw).await? {
88 Response::DidKey(key) => Ok(key),
89 _ => Err(AtprotoAppClientError::InvalidResponse("Invalid response")),
90 }
91 }
92
93 pub async fn sign_plc_operation(
94 &mut self,
95 key_index: u32,
96 operation: PlcOperation,
97 previous: Option<SignedPlcOperation>,
98 ) -> Result<Vec<u8>, AtprotoAppClientError> {
99 let msg = postcard::to_allocvec(&Request::SignPlcOperation {
100 key_index,
101 previous,
102 operation,
103 })
104 .map_err(|e| {
105 eprintln!("{:?}", e);
106 AtprotoAppClientError::GenericError("Failed to serialize SignPlcOperation request")
107 })?;
108
109 let response_raw = self.send_message(&msg).await?;
110 match Self::parse_response(&response_raw).await? {
111 Response::Signature(sig) => Ok(sig),
112 _ => Err(AtprotoAppClientError::InvalidResponse("Invalid response")),
113 }
114 }
115
116 pub async fn exit(&mut self) -> Result<i32, AtprotoAppClientError> {
117 let msg = postcard::to_allocvec(&Request::Exit)
118 .map_err(|_| AtprotoAppClientError::GenericError("Failed to serialize Exit request"))?;
119 let response_raw = self.send_message(&msg).await?;
120
121 match Self::parse_response(&response_raw).await {
122 Ok(_) => Err(AtprotoAppClientError::InvalidResponse(
123 "Exit message shouldn't return!",
124 )),
125 Err(e) => match e {
126 AtprotoAppClientError::VAppExecutionError(VAppExecutionError::AppExited(
127 status,
128 )) => Ok(status),
129 e => {
130 println!("Unexpected error on exit: {:?}", e);
131 Err(AtprotoAppClientError::InvalidResponse(
132 "Unexpected error on exit",
133 ))
134 }
135 },
136 }
137 }
138}