1use std::marker::PhantomData;
2
3use thiserror::Error;
4
5use crate::_internal::Handler;
6use crate::wit;
7
8pub use crate::_internal::global_get_public_keys as get_public_keys;
9
10#[derive(Debug, Error)]
11pub enum Error {
12 #[error("internal error: {0}")]
13 Internal(String),
14 #[error("bad config")]
15 BadConfig,
16 #[error("bad params")]
17 BadParams,
18 #[error("bad utxo")]
19 BadUtxo,
20 #[error("bad tx")]
21 BadTx,
22 #[error("event mismatch, expected {0}")]
23 EventMismatch(String),
24 #[error("kv error: {0}")]
25 KV(wit::balius::app::kv::KvError),
26 #[error("ledger error: {0}")]
27 Ledger(wit::balius::app::ledger::LedgerError),
28 #[error("sign error: {0}")]
29 Sign(wit::balius::app::sign::SignError),
30 #[error("http error: {0}")]
31 Http(wit::balius::app::http::ErrorCode),
32}
33
34impl From<Error> for wit::HandleError {
35 fn from(error: Error) -> Self {
36 match error {
37 Error::Internal(x) => wit::HandleError {
38 code: 0,
39 message: x,
40 },
41 Error::BadConfig => wit::HandleError {
42 code: 1,
43 message: "bad config".to_owned(),
44 },
45 Error::BadParams => wit::HandleError {
46 code: 2,
47 message: "bad params".to_owned(),
48 },
49 Error::KV(err) => wit::HandleError {
50 code: 3,
51 message: err.to_string(),
52 },
53 Error::Ledger(err) => wit::HandleError {
54 code: 4,
55 message: err.to_string(),
56 },
57 Error::Sign(err) => wit::HandleError {
58 code: 5,
59 message: err.to_string(),
60 },
61 Error::Http(err) => wit::HandleError {
62 code: 6,
63 message: err.to_string(),
64 },
65 Error::BadUtxo => wit::HandleError {
66 code: 7,
67 message: "bad utxo".to_owned(),
68 },
69 Error::BadTx => wit::HandleError {
70 code: 8,
71 message: "bad tx".to_owned(),
72 },
73 Error::EventMismatch(x) => wit::HandleError {
74 code: 9,
75 message: format!("event mismatch, expected {x}"),
76 },
77 }
78 }
79}
80
81impl From<serde_json::Error> for Error {
82 fn from(error: serde_json::Error) -> Self {
83 Error::Internal(error.to_string())
84 }
85}
86
87impl From<wit::balius::app::kv::KvError> for Error {
88 fn from(error: wit::balius::app::kv::KvError) -> Self {
89 Error::KV(error)
90 }
91}
92
93impl From<wit::balius::app::ledger::LedgerError> for Error {
94 fn from(error: wit::balius::app::ledger::LedgerError) -> Self {
95 Error::Ledger(error)
96 }
97}
98
99impl From<wit::balius::app::sign::SignError> for Error {
100 fn from(error: wit::balius::app::sign::SignError) -> Self {
101 Error::Sign(error)
102 }
103}
104
105impl From<wit::balius::app::http::ErrorCode> for Error {
106 fn from(error: wit::balius::app::http::ErrorCode) -> Self {
107 Error::Http(error)
108 }
109}
110
111impl From<crate::txbuilder::BuildError> for Error {
112 fn from(error: crate::txbuilder::BuildError) -> Self {
113 Error::Internal(error.to_string())
114 }
115}
116
117pub type WorkerResult<T> = std::result::Result<T, Error>;
118
119pub struct FnHandler<F, C, E, R>
120where
121 F: Fn(C, E) -> WorkerResult<R> + 'static,
122 C: TryFrom<wit::Config>,
123 E: TryFrom<wit::Event>,
124 R: TryInto<wit::Response>,
125{
126 func: F,
127 phantom: PhantomData<(C, E)>,
128}
129
130impl<F, C, E, R> Handler for FnHandler<F, C, E, R>
131where
132 C: TryFrom<wit::Config, Error = Error> + Send + Sync + 'static,
133 E: TryFrom<wit::Event, Error = Error> + Send + Sync + 'static,
134 R: TryInto<wit::Response, Error = Error> + Send + Sync + 'static,
135 F: Fn(C, E) -> WorkerResult<R> + Send + Sync + 'static,
136{
137 fn handle(
138 &self,
139 config: wit::Config,
140 event: wit::Event,
141 ) -> Result<wit::Response, wit::HandleError> {
142 let config: C = config.try_into()?;
143 let event: E = event.try_into()?;
144 let response = (self.func)(config, event)?;
145 Ok(response.try_into()?)
146 }
147}
148
149impl<F, C, E, R> From<F> for FnHandler<F, C, E, R>
150where
151 C: TryFrom<wit::Config, Error = Error> + Send + Sync + 'static,
152 E: TryFrom<wit::Event, Error = Error> + Send + Sync + 'static,
153 R: TryInto<wit::Response, Error = Error> + Send + Sync + 'static,
154 F: Fn(C, E) -> WorkerResult<R> + Send + Sync + 'static,
155{
156 fn from(func: F) -> Self {
157 FnHandler {
158 func,
159 phantom: PhantomData,
160 }
161 }
162}
163
164pub struct Ack;
165
166impl TryFrom<Ack> for wit::Response {
167 type Error = Error;
168
169 fn try_from(_: Ack) -> Result<Self, Self::Error> {
170 Ok(wit::Response::Acknowledge)
171 }
172}
173impl TryFrom<()> for wit::Response {
175 type Error = Error;
176
177 fn try_from(_: ()) -> Result<Self, Self::Error> {
178 Ok(wit::Response::Acknowledge)
179 }
180}
181
182pub struct Config<T>(pub T);
183
184impl<T> TryFrom<wit::Config> for Config<T>
185where
186 T: serde::de::DeserializeOwned,
187{
188 type Error = Error;
189
190 fn try_from(config: wit::Config) -> Result<Self, Self::Error> {
191 let t = serde_json::from_slice(config.as_slice()).map_err(|_| Error::BadConfig)?;
192 Ok(Config(t))
193 }
194}
195
196impl<T> std::ops::Deref for Config<T> {
197 type Target = T;
198
199 fn deref(&self) -> &Self::Target {
200 &self.0
201 }
202}
203
204pub struct Params<T>(pub T);
205
206impl<T> TryFrom<wit::Event> for Params<T>
207where
208 T: serde::de::DeserializeOwned,
209{
210 type Error = Error;
211
212 fn try_from(value: wit::Event) -> Result<Self, Self::Error> {
213 let bytes = match value {
214 wit::Event::Request(x) => x,
215 _ => todo!(),
216 };
217
218 let t = serde_json::from_slice(bytes.as_slice()).map_err(|_| Error::BadParams)?;
219 Ok(Params(t))
220 }
221}
222
223impl<T> From<Params<T>> for wit::Response
224where
225 T: serde::Serialize,
226{
227 fn from(value: Params<T>) -> Self {
228 Self::Json(serde_json::to_vec(&value.0).unwrap())
229 }
230}
231
232impl<T> std::ops::Deref for Params<T> {
233 type Target = T;
234
235 fn deref(&self) -> &Self::Target {
236 &self.0
237 }
238}
239
240pub struct Json<T>(pub T);
241
242impl<T> TryFrom<Json<T>> for wit::Response
243where
244 T: serde::Serialize,
245{
246 type Error = Error;
247
248 fn try_from(value: Json<T>) -> Result<Self, Self::Error> {
249 let bytes = serde_json::to_vec(&value.0)?;
250 Ok(wit::Response::Json(bytes))
251 }
252}
253
254impl<T> std::ops::Deref for Json<T> {
255 type Target = T;
256
257 fn deref(&self) -> &Self::Target {
258 &self.0
259 }
260}
261
262pub struct Utxo<D> {
263 pub block_hash: Vec<u8>,
264 pub block_height: u64,
265 pub block_slot: u64,
266 pub tx_hash: Vec<u8>,
267 pub index: u64,
268 pub utxo: utxorpc_spec::utxorpc::v1alpha::cardano::TxOutput,
269 pub datum: Option<D>,
270}
271
272impl<D> TryFrom<wit::Event> for Utxo<D> {
273 type Error = Error;
274
275 fn try_from(value: wit::Event) -> Result<Self, Self::Error> {
276 use prost::Message;
277
278 let utxo = match value {
279 wit::Event::Utxo(x) => x,
280 wit::Event::UtxoUndo(x) => x,
281 _ => return Err(Error::EventMismatch("utxo|utxoundo".to_owned())),
282 };
283
284 let block_hash = utxo.block.block_hash;
285 let block_height = utxo.block.block_height;
286 let block_slot = utxo.block.block_slot;
287 let tx_hash = utxo.ref_.tx_hash;
288 let index = utxo.ref_.txo_index as u64;
289 let utxo = Message::decode(utxo.body.as_slice()).map_err(|_| Self::Error::BadUtxo)?;
290
291 Ok(Utxo {
292 block_hash,
293 block_height,
294 block_slot,
295 tx_hash,
296 index,
297 utxo,
298 datum: None,
299 })
300 }
301}
302
303pub struct Tx {
304 pub block_hash: Vec<u8>,
305 pub block_height: u64,
306 pub block_slot: u64,
307 pub hash: Vec<u8>,
308 pub tx: utxorpc_spec::utxorpc::v1alpha::cardano::Tx,
309}
310
311impl TryFrom<wit::Event> for Tx {
312 type Error = Error;
313
314 fn try_from(value: wit::Event) -> Result<Self, Self::Error> {
315 use prost::Message;
316
317 let tx = match value {
318 wit::Event::Tx(x) => x,
319 wit::Event::TxUndo(x) => x,
320 _ => return Err(Error::EventMismatch("tx|tx-undo".to_owned())),
321 };
322
323 let block_hash = tx.block.block_hash;
324 let block_height = tx.block.block_height;
325 let block_slot = tx.block.block_slot;
326 let hash = tx.hash;
327 let tx = Message::decode(tx.body.as_slice()).map_err(|_| Self::Error::BadUtxo)?;
328
329 Ok(Self {
330 block_hash,
331 block_height,
332 block_slot,
333 hash,
334 tx,
335 })
336 }
337}
338
339pub struct NewTx(pub Box<dyn crate::txbuilder::TxExpr>);
340
341impl TryInto<wit::Response> for NewTx {
342 type Error = Error;
343
344 fn try_into(self) -> Result<wit::Response, Self::Error> {
345 let ledger = crate::txbuilder::ExtLedgerFacade;
346 let tx = crate::txbuilder::build(self.0, ledger)?;
347 let cbor = pallas_codec::minicbor::to_vec(&tx).unwrap();
348 Ok(wit::Response::PartialTx(cbor))
349 }
350}
351
352pub struct UtxoMatcher {
353 address: Option<Vec<u8>>,
354}
355
356impl UtxoMatcher {
357 pub fn all() -> Self {
358 Self { address: None }
359 }
360
361 pub fn by_address(address: Vec<u8>) -> Self {
362 Self {
363 address: Some(address),
364 }
365 }
366}
367
368impl From<UtxoMatcher> for wit::balius::app::driver::UtxoPattern {
369 fn from(value: UtxoMatcher) -> Self {
370 Self {
371 address: value.address,
372 token: None,
373 }
374 }
375}
376
377impl crate::_internal::Worker {
378 pub fn new() -> Self {
379 Self::default()
380 }
381
382 pub(crate) fn init(&mut self, config: wit::Config) {
383 self.config = Some(config);
384 }
385
386 pub fn with_signer(mut self, key: &str, algorithm: &str) -> Self {
387 self.requested_signers
388 .insert(key.to_string(), algorithm.to_string());
389 self
390 }
391
392 pub fn with_request_handler(mut self, method: &str, handler: impl Handler + 'static) -> Self {
393 self.channels.insert(
394 self.channels.len() as u32,
395 crate::_internal::Channel {
396 handler: Box::new(handler),
397 pattern: wit::balius::app::driver::EventPattern::Request(method.to_owned()),
398 },
399 );
400
401 self
402 }
403
404 pub fn with_utxo_handler(
405 mut self,
406 pattern: impl Into<wit::balius::app::driver::UtxoPattern>,
407 handler: impl Handler + 'static,
408 ) -> Self {
409 self.channels.insert(
410 self.channels.len() as u32,
411 crate::_internal::Channel {
412 handler: Box::new(handler),
413 pattern: wit::balius::app::driver::EventPattern::Utxo(pattern.into()),
414 },
415 );
416
417 self
418 }
419
420 pub fn with_tx_handler(
421 mut self,
422 pattern: impl Into<wit::balius::app::driver::UtxoPattern>,
423 handler: impl Handler + 'static,
424 ) -> Self {
425 self.channels.insert(
426 self.channels.len() as u32,
427 crate::_internal::Channel {
428 handler: Box::new(handler),
429 pattern: wit::balius::app::driver::EventPattern::Tx(pattern.into()),
430 },
431 );
432
433 self
434 }
435}