Compare commits
4 Commits
133-list-a
...
v2.1.17
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
373a5265a0 | ||
|
|
060e43590d | ||
|
|
f51ba984ca | ||
|
|
66ebc8a030 |
@@ -9,7 +9,7 @@ homepage = "https://github.com/cocool97/adb_client"
|
||||
keywords = ["adb", "android", "tcp", "usb"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/cocool97/adb_client"
|
||||
version = "2.1.16"
|
||||
version = "2.1.17"
|
||||
rust-version = "1.85.1"
|
||||
|
||||
# To build locally when working on a new release
|
||||
|
||||
@@ -16,7 +16,6 @@ anyhow = { version = "1.0.94" }
|
||||
clap = { version = "4.5.23", features = ["derive"] }
|
||||
env_logger = { version = "0.11.5" }
|
||||
log = { version = "0.4.26" }
|
||||
tabwriter = { version = "1.4.1" }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
termios = { version = "0.3.3" }
|
||||
|
||||
@@ -8,22 +8,20 @@ mod models;
|
||||
mod utils;
|
||||
|
||||
use adb_client::{
|
||||
ADBDeviceExt, ADBDeviceInfo, ADBServer, ADBServerDevice, ADBTcpDevice, ADBUSBDevice,
|
||||
MDNSDiscoveryService, find_all_connected_adb_devices,
|
||||
ADBDeviceExt, ADBServer, ADBServerDevice, ADBTcpDevice, ADBUSBDevice, MDNSDiscoveryService,
|
||||
};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use adb_termios::ADBTermios;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use handlers::{handle_emulator_commands, handle_host_commands, handle_local_commands};
|
||||
use models::{DeviceCommands, LocalCommand, MainCommand, Opts};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{Write, stdout};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use tabwriter::TabWriter;
|
||||
use utils::setup_logger;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
@@ -63,34 +61,6 @@ fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
MainCommand::Usb(usb_command) => {
|
||||
if usb_command.list_devices {
|
||||
let devices = find_all_connected_adb_devices()?;
|
||||
|
||||
let mut writer = TabWriter::new(stdout()).alignment(tabwriter::Alignment::Center);
|
||||
writeln!(writer, "Index\tVendor ID\tProduct ID\tDevice Description")?;
|
||||
writeln!(writer, "-----\t---------\t----------\t----------------")?;
|
||||
|
||||
for (
|
||||
index,
|
||||
ADBDeviceInfo {
|
||||
vendor_id,
|
||||
product_id,
|
||||
device_description,
|
||||
},
|
||||
) in devices.iter().enumerate()
|
||||
{
|
||||
writeln!(
|
||||
writer,
|
||||
"#{}\t{:04x}\t{:04x}\t{}",
|
||||
index, vendor_id, product_id, device_description
|
||||
)?;
|
||||
}
|
||||
|
||||
writer.flush()?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let device = match (usb_command.vendor_id, usb_command.product_id) {
|
||||
(Some(vid), Some(pid)) => match usb_command.path_to_private_key {
|
||||
Some(pk) => ADBUSBDevice::new_with_custom_private_key(vid, pid, pk)?,
|
||||
@@ -106,11 +76,7 @@ fn main() -> Result<()> {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
match usb_command.commands {
|
||||
Some(commands) => (device.boxed(), commands),
|
||||
None => bail!("no command provided"),
|
||||
}
|
||||
(device.boxed(), usb_command.commands)
|
||||
}
|
||||
MainCommand::Tcp(tcp_command) => {
|
||||
let device = ADBTcpDevice::new(tcp_command.address)?;
|
||||
|
||||
@@ -20,9 +20,6 @@ pub struct UsbCommand {
|
||||
/// Path to a custom private key to use for authentication
|
||||
#[clap(short = 'k', long = "private-key")]
|
||||
pub path_to_private_key: Option<PathBuf>,
|
||||
/// List all connected Android devices
|
||||
#[clap(short = 'l', long = "list")]
|
||||
pub list_devices: bool,
|
||||
#[clap(subcommand)]
|
||||
pub commands: Option<DeviceCommands>,
|
||||
pub commands: DeviceCommands,
|
||||
}
|
||||
|
||||
@@ -35,80 +35,28 @@ pub fn read_adb_private_key<P: AsRef<Path>>(private_key_path: P) -> Result<Optio
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an Android device connected via USB
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ADBDeviceInfo {
|
||||
/// Vendor ID of the device
|
||||
pub vendor_id: u16,
|
||||
/// Product ID of the device
|
||||
pub product_id: u16,
|
||||
/// Textual description of the device
|
||||
pub device_description: String,
|
||||
}
|
||||
|
||||
/// Find and return a list of all connected Android devices with known interface class and subclass values
|
||||
pub fn find_all_connected_adb_devices() -> Result<Vec<ADBDeviceInfo>> {
|
||||
/// Search for adb devices with known interface class and subclass values
|
||||
pub fn search_adb_devices() -> Result<Option<(u16, u16)>> {
|
||||
let mut found_devices = vec![];
|
||||
|
||||
for device in rusb::devices()?.iter() {
|
||||
let Ok(des) = device.device_descriptor() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if is_adb_device(&device, &des) {
|
||||
let device_handle = match device.open() {
|
||||
Ok(h) => h,
|
||||
Err(_) => {
|
||||
found_devices.push(ADBDeviceInfo {
|
||||
vendor_id: des.vendor_id(),
|
||||
product_id: des.product_id(),
|
||||
device_description: "Unknown device".to_string(),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let manufacturer = device_handle
|
||||
.read_manufacturer_string_ascii(&des)
|
||||
.unwrap_or_else(|_| "Unknown".to_string());
|
||||
|
||||
let product = device_handle
|
||||
.read_product_string_ascii(&des)
|
||||
.unwrap_or_else(|_| "Unknown".to_string());
|
||||
|
||||
let device_description = format!("{} {}", manufacturer, product);
|
||||
|
||||
found_devices.push(ADBDeviceInfo {
|
||||
vendor_id: des.vendor_id(),
|
||||
product_id: des.product_id(),
|
||||
device_description,
|
||||
});
|
||||
log::debug!(
|
||||
"Autodetect device {:04x}:{:04x}",
|
||||
des.vendor_id(),
|
||||
des.product_id()
|
||||
);
|
||||
found_devices.push((des.vendor_id(), des.product_id()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(found_devices)
|
||||
}
|
||||
|
||||
/// Find and return an USB-connected Android device with known interface class and subclass values.
|
||||
///
|
||||
/// Returns the first device found or None if no device is found.
|
||||
/// If multiple devices are found, an error is returned.
|
||||
pub fn get_single_connected_adb_device() -> Result<Option<ADBDeviceInfo>> {
|
||||
let found_devices = find_all_connected_adb_devices()?;
|
||||
match (found_devices.first(), found_devices.get(1)) {
|
||||
(None, _) => Ok(None),
|
||||
(Some(device_info), None) => {
|
||||
log::debug!(
|
||||
"Autodetect device {:04x}:{:04x} - {}",
|
||||
device_info.vendor_id,
|
||||
device_info.product_id,
|
||||
device_info.device_description
|
||||
);
|
||||
Ok(Some(device_info.clone()))
|
||||
}
|
||||
(Some(device_1), Some(device_2)) => Err(RustADBError::DeviceNotFound(format!(
|
||||
"Found two Android devices {:04x}:{:04x} and {:04x}:{:04x}",
|
||||
device_1.vendor_id, device_1.product_id, device_2.vendor_id, device_2.product_id
|
||||
(Some(identifiers), None) => Ok(Some(*identifiers)),
|
||||
(Some((vid1, pid1)), Some((vid2, pid2))) => Err(RustADBError::DeviceNotFound(format!(
|
||||
"Found two Android devices {vid1:04x}:{pid1:04x} and {vid2:04x}:{pid2:04x}",
|
||||
))),
|
||||
}
|
||||
}
|
||||
@@ -219,12 +167,10 @@ impl ADBUSBDevice {
|
||||
|
||||
/// autodetect connected ADB devices and establish a connection with the first device found using a custom private key path
|
||||
pub fn autodetect_with_custom_private_key(private_key_path: PathBuf) -> Result<Self> {
|
||||
match get_single_connected_adb_device()? {
|
||||
Some(device_info) => ADBUSBDevice::new_with_custom_private_key(
|
||||
device_info.vendor_id,
|
||||
device_info.product_id,
|
||||
private_key_path,
|
||||
),
|
||||
match search_adb_devices()? {
|
||||
Some((vendor_id, product_id)) => {
|
||||
ADBUSBDevice::new_with_custom_private_key(vendor_id, product_id, private_key_path)
|
||||
}
|
||||
_ => Err(RustADBError::DeviceNotFound(
|
||||
"cannot find USB devices matching the signature of an ADB device".into(),
|
||||
)),
|
||||
|
||||
@@ -12,8 +12,7 @@ use adb_message_device::ADBMessageDevice;
|
||||
pub use adb_tcp_device::ADBTcpDevice;
|
||||
pub use adb_transport_message::{ADBTransportMessage, ADBTransportMessageHeader};
|
||||
pub use adb_usb_device::{
|
||||
ADBDeviceInfo, ADBUSBDevice, find_all_connected_adb_devices, get_default_adb_key_path,
|
||||
get_single_connected_adb_device, is_adb_device,
|
||||
ADBUSBDevice, get_default_adb_key_path, is_adb_device, search_adb_devices,
|
||||
};
|
||||
pub use message_writer::MessageWriter;
|
||||
pub use models::{ADBRsaKey, MessageCommand, MessageSubcommand};
|
||||
|
||||
@@ -17,10 +17,7 @@ mod transports;
|
||||
mod utils;
|
||||
|
||||
pub use adb_device_ext::ADBDeviceExt;
|
||||
pub use device::{
|
||||
ADBDeviceInfo, ADBTcpDevice, ADBUSBDevice, find_all_connected_adb_devices,
|
||||
get_single_connected_adb_device, is_adb_device,
|
||||
};
|
||||
pub use device::{ADBTcpDevice, ADBUSBDevice, is_adb_device, search_adb_devices};
|
||||
pub use emulator_device::ADBEmulatorDevice;
|
||||
pub use error::{Result, RustADBError};
|
||||
pub use mdns::*;
|
||||
|
||||
@@ -93,7 +93,7 @@ impl TryFrom<&[u8]> for DeviceLong {
|
||||
.ok_or(RustADBError::RegexParsingError)?
|
||||
.as_bytes(),
|
||||
)?,
|
||||
16,
|
||||
10,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -23,21 +23,26 @@ impl<W: Write> LogFilter<W> {
|
||||
|
||||
impl<W: Write> Write for LogFilter<W> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
// Add newly received bytes to the internal buffer
|
||||
self.buffer.extend_from_slice(buf);
|
||||
|
||||
let buf_clone = self.buffer.clone();
|
||||
let mut lines = buf_clone.split_inclusive(|&byte| byte == b'\n').peekable();
|
||||
let mut processed = 0;
|
||||
while let Some(pos) = self.buffer[processed..].iter().position(|&b| b == b'\n') {
|
||||
// Found a newline, need to process it
|
||||
let end = processed + pos + 1; // +1 to include the '\n'
|
||||
let line = &self.buffer[processed..end];
|
||||
|
||||
while let Some(line) = lines.next() {
|
||||
if lines.peek().is_some() {
|
||||
if self.should_write(line) {
|
||||
self.writer.write_all(line)?;
|
||||
}
|
||||
} else {
|
||||
// This is the last (unfinished) element, we keep it for next round
|
||||
self.buffer = line.to_vec();
|
||||
break;
|
||||
if self.should_write(line) {
|
||||
self.writer.write_all(line)?;
|
||||
}
|
||||
|
||||
processed = end;
|
||||
}
|
||||
|
||||
// Keep only remaining bytes after the last complete line
|
||||
if processed > 0 {
|
||||
self.buffer.copy_within(processed.., 0);
|
||||
self.buffer.truncate(self.buffer.len() - processed);
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
|
||||
Reference in New Issue
Block a user