ledger_lib/provider/
mod.rs1use std::time::Duration;
5
6use tokio::sync::{
7 mpsc::{unbounded_channel, UnboundedSender},
8 OnceCell,
9};
10
11mod context;
12use context::ProviderContext;
13
14use crate::{error::Error, info::LedgerInfo, transport::Transport, Exchange, Filters};
15
16pub struct LedgerProvider {
18 req_tx: ReqChannel,
19}
20
21#[derive(Debug)]
23pub struct LedgerHandle {
24 pub info: LedgerInfo,
25
26 index: usize,
28
29 req_tx: ReqChannel,
31}
32
33#[derive(Clone, Debug, PartialEq)]
35pub enum LedgerReq {
36 List(Filters),
38
39 Connect(LedgerInfo),
41
42 Req(usize, Vec<u8>, Duration),
44
45 Close(usize),
47}
48
49#[derive(Debug)]
51pub enum LedgerResp {
52 Devices(Vec<LedgerInfo>),
54
55 Handle(usize),
57
58 Resp(Vec<u8>),
60
61 Error(Error),
63}
64
65pub type ReqChannel = UnboundedSender<(LedgerReq, UnboundedSender<LedgerResp>)>;
67
68static PROVIDER_CTX: OnceCell<ProviderContext> = OnceCell::const_new();
70
71impl LedgerProvider {
72 pub async fn init() -> Self {
74 let ctx = PROVIDER_CTX
76 .get_or_init(|| async { ProviderContext::new().await })
77 .await;
78
79 Self {
81 req_tx: ctx.req_tx(),
82 }
83 }
84}
85
86impl Transport for LedgerProvider {
88 type Device = LedgerHandle;
89 type Info = LedgerInfo;
90 type Filters = Filters;
91
92 async fn list(&mut self, filters: Filters) -> Result<Vec<LedgerInfo>, Error> {
94 let (tx, mut rx) = unbounded_channel::<LedgerResp>();
95
96 self.req_tx
98 .send((LedgerReq::List(filters), tx))
99 .map_err(|_| Error::RequestChannelClosed)?;
100
101 match rx.recv().await {
103 Some(LedgerResp::Devices(i)) => Ok(i),
104 Some(LedgerResp::Error(e)) => Err(e),
105 Some(LedgerResp::Resp(_) | LedgerResp::Handle(_)) => {
106 Err(Error::UnexpectedResponseWhileListingDevices)
107 }
108 None => Err(Error::RequestResponseChannelClosed),
109 }
110 }
111
112 async fn connect(&mut self, info: LedgerInfo) -> Result<LedgerHandle, Error> {
114 let (tx, mut rx) = unbounded_channel::<LedgerResp>();
115
116 self.req_tx
118 .send((LedgerReq::Connect(info.clone()), tx))
119 .map_err(|_| Error::RequestChannelClosed)?;
120
121 match rx.recv().await {
123 Some(LedgerResp::Handle(index)) => Ok(LedgerHandle {
124 info,
125 index,
126 req_tx: self.req_tx.clone(),
127 }),
128 Some(LedgerResp::Error(e)) => Err(e),
129 Some(LedgerResp::Devices(_) | LedgerResp::Resp(_)) => {
130 Err(Error::UnexpectedResponseWhileConnecting)
131 }
132 None => Err(Error::RequestResponseChannelClosed),
133 }
134 }
135}
136
137impl Exchange for LedgerHandle {
139 async fn exchange(&mut self, command: &[u8], timeout: Duration) -> Result<Vec<u8>, Error> {
140 let (tx, mut rx) = unbounded_channel::<LedgerResp>();
141
142 self.req_tx
144 .send((LedgerReq::Req(self.index, command.to_vec(), timeout), tx))
145 .map_err(|_| Error::RequestChannelClosed)?;
146
147 match rx.recv().await {
149 Some(LedgerResp::Resp(data)) => Ok(data),
150 Some(LedgerResp::Error(e)) => Err(e),
151 Some(LedgerResp::Devices(_) | LedgerResp::Handle(_)) => {
152 Err(Error::UnexpectedResponseWhileExchangingData)
153 }
154 None => Err(Error::RequestResponseChannelClosed),
155 }
156 }
157}
158
159impl Drop for LedgerHandle {
161 fn drop(&mut self) {
162 let (tx, _rx) = unbounded_channel::<LedgerResp>();
163 let _ = self.req_tx.send((LedgerReq::Close(self.index), tx));
164 }
165}