ledger_lib/transport/
mod.rs1use std::{fmt::Debug, marker::PhantomData, sync::MutexGuard, time::Duration};
7
8#[cfg(feature = "transport_ble")]
9use tracing::warn;
10
11use tracing::debug;
12
13#[cfg(feature = "transport_usb")]
14mod usb;
15#[cfg(feature = "transport_usb")]
16pub use usb::{UsbDevice, UsbInfo, UsbTransport};
17
18#[cfg(feature = "transport_ble")]
19mod ble;
20#[cfg(feature = "transport_ble")]
21pub use ble::{BleDevice, BleInfo, BleTransport};
22
23#[cfg(feature = "transport_tcp")]
24mod tcp;
25#[cfg(feature = "transport_tcp")]
26pub use tcp::{TcpDevice, TcpInfo, TcpTransport};
27
28use crate::{
29 info::{ConnInfo, LedgerInfo},
30 Error, Filters, NonSendExchange,
31};
32
33pub type PhantomNonSend = PhantomData<MutexGuard<'static, ()>>;
35
36#[allow(async_fn_in_trait)]
38pub trait Transport {
39 type Filters: Default + Debug;
41 type Info: Debug;
43 type Device: NonSendExchange;
45
46 async fn list(&mut self, filters: Self::Filters) -> Result<Vec<LedgerInfo>, Error>;
48
49 async fn connect(&mut self, info: Self::Info) -> Result<Self::Device, Error>;
51}
52
53impl<T: Transport + Send> Transport for &mut T
55where
56 <T as Transport>::Device: Send,
57 <T as Transport>::Filters: Send,
58 <T as Transport>::Info: Send,
59{
60 type Filters = <T as Transport>::Filters;
61 type Info = <T as Transport>::Info;
62 type Device = <T as Transport>::Device;
63
64 async fn list(&mut self, filters: Self::Filters) -> Result<Vec<LedgerInfo>, Error> {
65 <T as Transport>::list(self, filters).await
66 }
67 async fn connect(&mut self, info: Self::Info) -> Result<Self::Device, Error> {
68 <T as Transport>::connect(self, info).await
69 }
70}
71
72pub struct GenericTransport {
75 #[cfg(feature = "transport_usb")]
76 usb: UsbTransport,
77
78 #[cfg(feature = "transport_ble")]
79 ble: BleTransport,
80
81 #[cfg(feature = "transport_tcp")]
82 tcp: TcpTransport,
83}
84
85pub enum GenericDevice {
88 #[cfg(feature = "transport_usb")]
89 Usb(UsbDevice),
90
91 #[cfg(feature = "transport_ble")]
92 Ble(BleDevice),
93
94 #[cfg(feature = "transport_tcp")]
95 Tcp(TcpDevice),
96}
97
98impl GenericTransport {
99 pub async fn new() -> Result<Self, Error> {
101 debug!("Initialising GenericTransport");
102
103 Ok(Self {
104 #[cfg(feature = "transport_usb")]
105 usb: UsbTransport::new()?,
106
107 #[cfg(feature = "transport_ble")]
108 ble: BleTransport::new().await?,
109
110 #[cfg(feature = "transport_tcp")]
111 tcp: TcpTransport::new()?,
112 })
113 }
114}
115
116impl Transport for GenericTransport {
117 type Filters = Filters;
118 type Info = LedgerInfo;
119 type Device = GenericDevice;
120
121 async fn list(&mut self, filters: Filters) -> Result<Vec<LedgerInfo>, Error> {
123 let mut devices = vec![];
124
125 #[cfg(feature = "transport_usb")]
126 if filters == Filters::Any || filters == Filters::Hid {
127 let mut d = self.usb.list(()).await?;
128 devices.append(&mut d);
129 }
130
131 #[cfg(feature = "transport_ble")]
132 if filters == Filters::Any || filters == Filters::Ble {
133 match self.ble.list(()).await {
137 Ok(mut d) => devices.append(&mut d),
138 Err(e) if filters == Filters::Any => {
139 warn!("BLE discovery failed: {e:?}");
140 }
141 Err(e) => return Err(e),
142 }
143 }
144
145 #[cfg(feature = "transport_tcp")]
146 if filters == Filters::Any || filters == Filters::Tcp {
147 let mut d = self.tcp.list(()).await?;
148 devices.append(&mut d);
149 }
150
151 Ok(devices)
152 }
153
154 async fn connect(&mut self, info: LedgerInfo) -> Result<GenericDevice, Error> {
157 debug!("Connecting to device: {:?}", info);
158
159 let d = match info.conn {
160 #[cfg(feature = "transport_usb")]
161 ConnInfo::Usb(i) => self.usb.connect(i).await.map(GenericDevice::Usb)?,
162 #[cfg(feature = "transport_tcp")]
163 ConnInfo::Tcp(i) => self.tcp.connect(i).await.map(GenericDevice::Tcp)?,
164 #[cfg(feature = "transport_ble")]
165 ConnInfo::Ble(i) => self.ble.connect(i).await.map(GenericDevice::Ble)?,
166 };
167
168 Ok(d)
169 }
170}
171
172impl GenericDevice {
173 pub fn info(&self) -> ConnInfo {
175 match self {
176 #[cfg(feature = "transport_usb")]
177 GenericDevice::Usb(d) => d.info.clone().into(),
178 #[cfg(feature = "transport_ble")]
179 GenericDevice::Ble(d) => d.info.clone().into(),
180 #[cfg(feature = "transport_tcp")]
181 GenericDevice::Tcp(d) => d.info.clone().into(),
182 }
183 }
184
185 pub(crate) async fn is_connected(&self) -> Result<bool, Error> {
186 match self {
187 #[cfg(feature = "transport_usb")]
188 GenericDevice::Usb(d) => d.is_connected().await,
189 #[cfg(feature = "transport_ble")]
190 GenericDevice::Ble(d) => d.is_connected().await,
191 #[cfg(feature = "transport_tcp")]
192 GenericDevice::Tcp(d) => d.is_connected().await,
193 }
194 }
195}
196
197impl NonSendExchange for GenericDevice {
198 async fn exchange(&mut self, command: &[u8], timeout: Duration) -> Result<Vec<u8>, Error> {
200 match self {
201 #[cfg(feature = "transport_usb")]
202 Self::Usb(d) => d.exchange(command, timeout).await,
203 #[cfg(feature = "transport_ble")]
204 Self::Ble(d) => d.exchange(command, timeout).await,
205 #[cfg(feature = "transport_tcp")]
206 Self::Tcp(d) => d.exchange(command, timeout).await,
207 }
208 }
209}
210
211#[cfg(feature = "transport_usb")]
212impl From<UsbDevice> for GenericDevice {
213 fn from(value: UsbDevice) -> Self {
214 Self::Usb(value)
215 }
216}
217
218#[cfg(feature = "transport_tcp")]
219impl From<TcpDevice> for GenericDevice {
220 fn from(value: TcpDevice) -> Self {
221 Self::Tcp(value)
222 }
223}
224
225#[cfg(feature = "transport_ble")]
226impl From<BleDevice> for GenericDevice {
227 fn from(value: BleDevice) -> Self {
228 Self::Ble(value)
229 }
230}