diff --git a/.github/workflows/rust-quality.yml b/.github/workflows/rust-quality.yml index 2b0dc43..f52b187 100644 --- a/.github/workflows/rust-quality.yml +++ b/.github/workflows/rust-quality.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v4 - run: rustup component add clippy - name: Run clippy - run : cargo clippy --all-features + run: cargo clippy --all-features fmt: name: "fmt" @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run formatter - run : cargo fmt --all --check + run: cargo fmt --all --check doc: name: "doc" @@ -29,7 +29,9 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run doc - run : cargo doc --all-features --keep-going + run: cargo doc --all-features --no-deps + env: + RUSTDOCFLAGS: "-D warnings" tests: name: "tests" @@ -37,4 +39,4 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run tests - run: cargo test --verbose \ No newline at end of file + run: cargo test --verbose diff --git a/adb_client/src/adb_device_ext.rs b/adb_client/src/adb_device_ext.rs index 2817a44..2d48fb1 100644 --- a/adb_client/src/adb_device_ext.rs +++ b/adb_client/src/adb_device_ext.rs @@ -4,18 +4,18 @@ use std::path::Path; use crate::models::AdbStatResponse; use crate::{RebootType, Result}; -/// Trait representing all features available on devices. +/// Trait representing all features available on both [`crate::ADBServerDevice`] and [`crate::ADBUSBDevice`] pub trait ADBDeviceExt { - /// Run 'command' in a shell on the device, and write its output and error streams into `output`. + /// Runs command in a shell on the device, and write its output and error streams into output. fn shell_command( &mut self, command: impl IntoIterator, output: W, ) -> Result<()>; - /// Start an interactive shell session on the device. - /// Input data is read from `reader` and write to `writer`. - /// `W` has a 'static bound as it is internally used in a thread. + /// Starts an interactive shell session on the device. + /// Input data is read from reader and write to writer. + /// W has a 'static bound as it is internally used in a thread. fn shell(&mut self, reader: R, writer: W) -> Result<()>; /// Display the stat information for a remote file diff --git a/adb_client/src/device/adb_usb_device.rs b/adb_client/src/device/adb_usb_device.rs index 1c3425c..2376e0b 100644 --- a/adb_client/src/device/adb_usb_device.rs +++ b/adb_client/src/device/adb_usb_device.rs @@ -15,13 +15,6 @@ use crate::ADBMessageTransport; use crate::ADBTransport; use crate::{Result, RustADBError, USBTransport}; -/// Represent a device reached and available over USB. -#[derive(Debug)] -pub struct ADBUSBDevice { - private_key: ADBRsaKey, - inner: ADBMessageDevice, -} - pub fn read_adb_private_key>(private_key_path: P) -> Result> { Ok(read_to_string(private_key_path.as_ref()).map(|pk| { match ADBRsaKey::new_from_pkcs8(&pk) { @@ -101,6 +94,13 @@ pub fn get_default_adb_key_path() -> Result { .ok_or(RustADBError::NoHomeDirectory) } +/// Represent a device reached and available over USB. +#[derive(Debug)] +pub struct ADBUSBDevice { + private_key: ADBRsaKey, + inner: ADBMessageDevice, +} + impl ADBUSBDevice { /// Instantiate a new [`ADBUSBDevice`] pub fn new(vendor_id: u16, product_id: u16) -> Result { @@ -112,6 +112,26 @@ impl ADBUSBDevice { vendor_id: u16, product_id: u16, private_key_path: PathBuf, + ) -> Result { + Self::new_from_transport_inner(USBTransport::new(vendor_id, product_id)?, private_key_path) + } + + /// Instantiate a new [`ADBUSBDevice`] from a [`USBTransport`] and an optional private key path. + pub fn new_from_transport( + transport: USBTransport, + private_key_path: Option, + ) -> Result { + let private_key_path = match private_key_path { + Some(private_key_path) => private_key_path, + None => get_default_adb_key_path()?, + }; + + Self::new_from_transport_inner(transport, private_key_path) + } + + fn new_from_transport_inner( + transport: USBTransport, + private_key_path: PathBuf, ) -> Result { let private_key = match read_adb_private_key(private_key_path)? { Some(pk) => pk, @@ -120,7 +140,7 @@ impl ADBUSBDevice { let mut s = Self { private_key, - inner: ADBMessageDevice::new(USBTransport::new(vendor_id, product_id)), + inner: ADBMessageDevice::new(transport), }; s.connect()?; diff --git a/adb_client/src/server_device/commands/list.rs b/adb_client/src/server_device/commands/list.rs index 2cb464a..27919be 100644 --- a/adb_client/src/server_device/commands/list.rs +++ b/adb_client/src/server_device/commands/list.rs @@ -9,7 +9,7 @@ use std::{ }; impl ADBServerDevice { - /// Lists files in `path` on the device. + /// Lists files in path on the device. pub fn list>(&mut self, path: A) -> Result<()> { let serial = self.identifier.clone(); self.connect()? diff --git a/adb_client/src/server_device/commands/recv.rs b/adb_client/src/server_device/commands/recv.rs index 250f470..165e961 100644 --- a/adb_client/src/server_device/commands/recv.rs +++ b/adb_client/src/server_device/commands/recv.rs @@ -69,7 +69,7 @@ impl Read for ADBRecvCommandReader { } impl ADBServerDevice { - /// Receives `path` to `stream` from the device. + /// Receives path to stream from the device. pub fn pull>(&mut self, path: A, stream: &mut dyn Write) -> Result<()> { let serial = self.identifier.clone(); self.connect()? diff --git a/adb_client/src/server_device/commands/send.rs b/adb_client/src/server_device/commands/send.rs index ca536cc..8dbf686 100644 --- a/adb_client/src/server_device/commands/send.rs +++ b/adb_client/src/server_device/commands/send.rs @@ -42,7 +42,7 @@ impl Write for ADBSendCommandWriter { } impl ADBServerDevice { - /// Send `stream` to `path` on the device. + /// Send stream to path on the device. pub fn push>(&mut self, stream: R, path: A) -> Result<()> { log::info!("Sending data to {}", path.as_ref()); let serial = self.identifier.clone(); diff --git a/adb_client/src/server_device/commands/stat.rs b/adb_client/src/server_device/commands/stat.rs index 0f3165d..015ac61 100644 --- a/adb_client/src/server_device/commands/stat.rs +++ b/adb_client/src/server_device/commands/stat.rs @@ -41,7 +41,7 @@ impl ADBServerDevice { } } - /// Stat file given as `path` on the device. + /// Stat file given as path on the device. pub fn stat>(&mut self, path: A) -> Result { let serial = self.identifier.clone(); self.connect()? diff --git a/adb_client/src/transports/usb_transport.rs b/adb_client/src/transports/usb_transport.rs index 31d3895..d28e85a 100644 --- a/adb_client/src/transports/usb_transport.rs +++ b/adb_client/src/transports/usb_transport.rs @@ -1,7 +1,8 @@ use std::{sync::Arc, time::Duration}; use rusb::{ - constants::LIBUSB_CLASS_VENDOR_SPEC, DeviceHandle, Direction, GlobalContext, TransferType, + constants::LIBUSB_CLASS_VENDOR_SPEC, Device, DeviceHandle, Direction, GlobalContext, + TransferType, }; use super::{ADBMessageTransport, ADBTransport}; @@ -19,18 +20,35 @@ struct Endpoint { /// Transport running on USB #[derive(Debug, Clone)] pub struct USBTransport { - vendor_id: u16, - product_id: u16, + device: Device, handle: Option>>, } impl USBTransport { - /// Instantiate a new [USBTransport] - pub fn new(vendor_id: u16, product_id: u16) -> Self { + /// Instantiate a new [`USBTransport`]. + /// Only the first device with given vendor_id and product_id is returned. + pub fn new(vendor_id: u16, product_id: u16) -> Result { + for device in rusb::devices()?.iter() { + if let Ok(descriptor) = device.device_descriptor() { + if descriptor.vendor_id() == vendor_id && descriptor.product_id() == product_id { + return Ok(Self::new_from_device(device)); + } + } + } + + Err(RustADBError::DeviceNotFound(format!( + "cannot find USB device with vendor_id={} and product_id={}", + vendor_id, product_id + ))) + } + + /// Instantiate a new [`USBTransport`] from a [`rusb::Device`]. + /// + /// Devices can be enumerated using [`rusb::devices()`] and then filtered out to get desired device. + pub fn new_from_device(rusb_device: rusb::Device) -> Self { Self { + device: rusb_device, handle: None, - vendor_id, - product_id, } } @@ -112,22 +130,8 @@ impl USBTransport { impl ADBTransport for USBTransport { fn connect(&mut self) -> crate::Result<()> { - for d in rusb::devices()?.iter() { - if let Ok(descriptor) = d.device_descriptor() { - if descriptor.vendor_id() == self.vendor_id - && descriptor.product_id() == self.product_id - { - self.handle = Some(Arc::new(d.open()?)); - - return Ok(()); - } - } - } - - Err(RustADBError::DeviceNotFound(format!( - "Cannot find device with vendor id {} and product id {}", - self.vendor_id, self.product_id - ))) + self.handle = Some(Arc::new(self.device.open()?)); + Ok(()) } fn disconnect(&mut self) -> crate::Result<()> {