Compare commits
1 Commits
133-list-a
...
websub
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4126c856d9 |
@@ -16,7 +16,6 @@ anyhow = { version = "1.0.94" }
|
|||||||
clap = { version = "4.5.23", features = ["derive"] }
|
clap = { version = "4.5.23", features = ["derive"] }
|
||||||
env_logger = { version = "0.11.5" }
|
env_logger = { version = "0.11.5" }
|
||||||
log = { version = "0.4.26" }
|
log = { version = "0.4.26" }
|
||||||
tabwriter = { version = "1.4.1" }
|
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
termios = { version = "0.3.3" }
|
termios = { version = "0.3.3" }
|
||||||
|
|||||||
@@ -8,22 +8,20 @@ mod models;
|
|||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use adb_client::{
|
use adb_client::{
|
||||||
ADBDeviceExt, ADBDeviceInfo, ADBServer, ADBServerDevice, ADBTcpDevice, ADBUSBDevice,
|
ADBDeviceExt, ADBServer, ADBServerDevice, ADBTcpDevice, ADBUSBDevice, MDNSDiscoveryService,
|
||||||
MDNSDiscoveryService, find_all_connected_adb_devices,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
use adb_termios::ADBTermios;
|
use adb_termios::ADBTermios;
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use handlers::{handle_emulator_commands, handle_host_commands, handle_local_commands};
|
use handlers::{handle_emulator_commands, handle_host_commands, handle_local_commands};
|
||||||
use models::{DeviceCommands, LocalCommand, MainCommand, Opts};
|
use models::{DeviceCommands, LocalCommand, MainCommand, Opts};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Write, stdout};
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tabwriter::TabWriter;
|
|
||||||
use utils::setup_logger;
|
use utils::setup_logger;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
@@ -63,34 +61,6 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
MainCommand::Usb(usb_command) => {
|
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) {
|
let device = match (usb_command.vendor_id, usb_command.product_id) {
|
||||||
(Some(vid), Some(pid)) => match usb_command.path_to_private_key {
|
(Some(vid), Some(pid)) => match usb_command.path_to_private_key {
|
||||||
Some(pk) => ADBUSBDevice::new_with_custom_private_key(vid, pid, pk)?,
|
Some(pk) => ADBUSBDevice::new_with_custom_private_key(vid, pid, pk)?,
|
||||||
@@ -106,11 +76,7 @@ fn main() -> Result<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
(device.boxed(), usb_command.commands)
|
||||||
match usb_command.commands {
|
|
||||||
Some(commands) => (device.boxed(), commands),
|
|
||||||
None => bail!("no command provided"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MainCommand::Tcp(tcp_command) => {
|
MainCommand::Tcp(tcp_command) => {
|
||||||
let device = ADBTcpDevice::new(tcp_command.address)?;
|
let device = ADBTcpDevice::new(tcp_command.address)?;
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ pub struct UsbCommand {
|
|||||||
/// Path to a custom private key to use for authentication
|
/// Path to a custom private key to use for authentication
|
||||||
#[clap(short = 'k', long = "private-key")]
|
#[clap(short = 'k', long = "private-key")]
|
||||||
pub path_to_private_key: Option<PathBuf>,
|
pub path_to_private_key: Option<PathBuf>,
|
||||||
/// List all connected Android devices
|
|
||||||
#[clap(short = 'l', long = "list")]
|
|
||||||
pub list_devices: bool,
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
pub commands: Option<DeviceCommands>,
|
pub commands: DeviceCommands,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ repository.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["mdns"]
|
||||||
|
mdns = ["dep:mdns-sd"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = { version = "0.22.1" }
|
base64 = { version = "0.22.1" }
|
||||||
bincode = { version = "1.3.3" }
|
bincode = { version = "1.3.3" }
|
||||||
@@ -18,9 +22,6 @@ chrono = { version = "0.4.40", default-features = false, features = ["std"] }
|
|||||||
homedir = { version = "= 0.3.4" }
|
homedir = { version = "= 0.3.4" }
|
||||||
image = { version = "0.25.5", default-features = false }
|
image = { version = "0.25.5", default-features = false }
|
||||||
log = { version = "0.4.26" }
|
log = { version = "0.4.26" }
|
||||||
mdns-sd = { version = "0.13.9", default-features = false, features = [
|
|
||||||
"logging",
|
|
||||||
] }
|
|
||||||
num-bigint = { version = "0.8.4", package = "num-bigint-dig" }
|
num-bigint = { version = "0.8.4", package = "num-bigint-dig" }
|
||||||
num-traits = { version = "0.2.19" }
|
num-traits = { version = "0.2.19" }
|
||||||
quick-protobuf = { version = "0.8.1" }
|
quick-protobuf = { version = "0.8.1" }
|
||||||
@@ -39,6 +40,11 @@ serde_repr = { version = "0.1.19" }
|
|||||||
sha1 = { version = "0.10.6", features = ["oid"] }
|
sha1 = { version = "0.10.6", features = ["oid"] }
|
||||||
thiserror = { version = "2.0.7" }
|
thiserror = { version = "2.0.7" }
|
||||||
|
|
||||||
|
# MDNS
|
||||||
|
mdns-sd = { version = "0.13.9", default-features = false, optional = true, features = [
|
||||||
|
"logging",
|
||||||
|
] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = { version = "1.0.93" }
|
anyhow = { version = "1.0.93" }
|
||||||
criterion = { version = "0.6.0" } # Used for benchmarks
|
criterion = { version = "0.6.0" } # Used for benchmarks
|
||||||
|
|||||||
@@ -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
|
/// Search for adb devices with known interface class and subclass values
|
||||||
#[derive(Clone, Debug)]
|
pub fn search_adb_devices() -> Result<Option<(u16, u16)>> {
|
||||||
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>> {
|
|
||||||
let mut found_devices = vec![];
|
let mut found_devices = vec![];
|
||||||
|
|
||||||
for device in rusb::devices()?.iter() {
|
for device in rusb::devices()?.iter() {
|
||||||
let Ok(des) = device.device_descriptor() else {
|
let Ok(des) = device.device_descriptor() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_adb_device(&device, &des) {
|
if is_adb_device(&device, &des) {
|
||||||
let device_handle = match device.open() {
|
log::debug!(
|
||||||
Ok(h) => h,
|
"Autodetect device {:04x}:{:04x}",
|
||||||
Err(_) => {
|
des.vendor_id(),
|
||||||
found_devices.push(ADBDeviceInfo {
|
des.product_id()
|
||||||
vendor_id: des.vendor_id(),
|
);
|
||||||
product_id: des.product_id(),
|
found_devices.push((des.vendor_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,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)) {
|
match (found_devices.first(), found_devices.get(1)) {
|
||||||
(None, _) => Ok(None),
|
(None, _) => Ok(None),
|
||||||
(Some(device_info), None) => {
|
(Some(identifiers), None) => Ok(Some(*identifiers)),
|
||||||
log::debug!(
|
(Some((vid1, pid1)), Some((vid2, pid2))) => Err(RustADBError::DeviceNotFound(format!(
|
||||||
"Autodetect device {:04x}:{:04x} - {}",
|
"Found two Android devices {vid1:04x}:{pid1:04x} and {vid2:04x}:{pid2: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
|
|
||||||
))),
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
/// 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> {
|
pub fn autodetect_with_custom_private_key(private_key_path: PathBuf) -> Result<Self> {
|
||||||
match get_single_connected_adb_device()? {
|
match search_adb_devices()? {
|
||||||
Some(device_info) => ADBUSBDevice::new_with_custom_private_key(
|
Some((vendor_id, product_id)) => {
|
||||||
device_info.vendor_id,
|
ADBUSBDevice::new_with_custom_private_key(vendor_id, product_id, private_key_path)
|
||||||
device_info.product_id,
|
}
|
||||||
private_key_path,
|
|
||||||
),
|
|
||||||
_ => Err(RustADBError::DeviceNotFound(
|
_ => Err(RustADBError::DeviceNotFound(
|
||||||
"cannot find USB devices matching the signature of an ADB device".into(),
|
"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_tcp_device::ADBTcpDevice;
|
||||||
pub use adb_transport_message::{ADBTransportMessage, ADBTransportMessageHeader};
|
pub use adb_transport_message::{ADBTransportMessage, ADBTransportMessageHeader};
|
||||||
pub use adb_usb_device::{
|
pub use adb_usb_device::{
|
||||||
ADBDeviceInfo, ADBUSBDevice, find_all_connected_adb_devices, get_default_adb_key_path,
|
ADBUSBDevice, get_default_adb_key_path, is_adb_device, search_adb_devices,
|
||||||
get_single_connected_adb_device, is_adb_device,
|
|
||||||
};
|
};
|
||||||
pub use message_writer::MessageWriter;
|
pub use message_writer::MessageWriter;
|
||||||
pub use models::{ADBRsaKey, MessageCommand, MessageSubcommand};
|
pub use models::{ADBRsaKey, MessageCommand, MessageSubcommand};
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ pub enum RustADBError {
|
|||||||
#[error("upgrade error: {0}")]
|
#[error("upgrade error: {0}")]
|
||||||
UpgradeError(String),
|
UpgradeError(String),
|
||||||
/// An error occurred while getting mdns devices
|
/// An error occurred while getting mdns devices
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
MDNSError(#[from] mdns_sd::Error),
|
MDNSError(#[from] mdns_sd::Error),
|
||||||
/// An error occurred while sending data to channel
|
/// An error occurred while sending data to channel
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ mod constants;
|
|||||||
mod device;
|
mod device;
|
||||||
mod emulator_device;
|
mod emulator_device;
|
||||||
mod error;
|
mod error;
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
mod mdns;
|
mod mdns;
|
||||||
mod models;
|
mod models;
|
||||||
mod server;
|
mod server;
|
||||||
@@ -17,12 +18,10 @@ mod transports;
|
|||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub use adb_device_ext::ADBDeviceExt;
|
pub use adb_device_ext::ADBDeviceExt;
|
||||||
pub use device::{
|
pub use device::{ADBTcpDevice, ADBUSBDevice, is_adb_device, search_adb_devices};
|
||||||
ADBDeviceInfo, ADBTcpDevice, ADBUSBDevice, find_all_connected_adb_devices,
|
|
||||||
get_single_connected_adb_device, is_adb_device,
|
|
||||||
};
|
|
||||||
pub use emulator_device::ADBEmulatorDevice;
|
pub use emulator_device::ADBEmulatorDevice;
|
||||||
pub use error::{Result, RustADBError};
|
pub use error::{Result, RustADBError};
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
pub use mdns::*;
|
pub use mdns::*;
|
||||||
pub use models::{AdbStatResponse, RebootType};
|
pub use models::{AdbStatResponse, RebootType};
|
||||||
pub use server::*;
|
pub use server::*;
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ pub(crate) enum AdbServerCommand {
|
|||||||
Pair(SocketAddrV4, String),
|
Pair(SocketAddrV4, String),
|
||||||
TransportAny,
|
TransportAny,
|
||||||
TransportSerial(String),
|
TransportSerial(String),
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
MDNSCheck,
|
MDNSCheck,
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
MDNSServices,
|
MDNSServices,
|
||||||
ServerStatus,
|
ServerStatus,
|
||||||
ReconnectOffline,
|
ReconnectOffline,
|
||||||
@@ -77,7 +79,9 @@ impl Display for AdbServerCommand {
|
|||||||
write!(f, "reverse:forward:{remote};{local}")
|
write!(f, "reverse:forward:{remote};{local}")
|
||||||
}
|
}
|
||||||
AdbServerCommand::ReverseRemoveAll => write!(f, "reverse:killforward-all"),
|
AdbServerCommand::ReverseRemoveAll => write!(f, "reverse:killforward-all"),
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
AdbServerCommand::MDNSCheck => write!(f, "host:mdns:check"),
|
AdbServerCommand::MDNSCheck => write!(f, "host:mdns:check"),
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
AdbServerCommand::MDNSServices => write!(f, "host:mdns:services"),
|
AdbServerCommand::MDNSServices => write!(f, "host:mdns:services"),
|
||||||
AdbServerCommand::ServerStatus => write!(f, "host:server-status"),
|
AdbServerCommand::ServerStatus => write!(f, "host:server-status"),
|
||||||
AdbServerCommand::Reconnect => write!(f, "reconnect"),
|
AdbServerCommand::Reconnect => write!(f, "reconnect"),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crate::{
|
|||||||
|
|
||||||
const OPENSCREEN_MDNS_BACKEND: &str = "ADB_MDNS_OPENSCREEN";
|
const OPENSCREEN_MDNS_BACKEND: &str = "ADB_MDNS_OPENSCREEN";
|
||||||
|
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
impl ADBServer {
|
impl ADBServer {
|
||||||
/// Check if mdns discovery is available
|
/// Check if mdns discovery is available
|
||||||
pub fn mdns_check(&mut self) -> Result<bool> {
|
pub fn mdns_check(&mut self) -> Result<bool> {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ mod connect;
|
|||||||
mod devices;
|
mod devices;
|
||||||
mod disconnect;
|
mod disconnect;
|
||||||
mod kill;
|
mod kill;
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
mod mdns;
|
mod mdns;
|
||||||
mod pair;
|
mod pair;
|
||||||
mod reconnect;
|
mod reconnect;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ mod adb_version;
|
|||||||
mod device_long;
|
mod device_long;
|
||||||
mod device_short;
|
mod device_short;
|
||||||
mod device_state;
|
mod device_state;
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
mod mdns_services;
|
mod mdns_services;
|
||||||
mod server_status;
|
mod server_status;
|
||||||
mod wait_for_device;
|
mod wait_for_device;
|
||||||
@@ -10,6 +11,7 @@ pub use adb_version::AdbVersion;
|
|||||||
pub use device_long::DeviceLong;
|
pub use device_long::DeviceLong;
|
||||||
pub use device_short::DeviceShort;
|
pub use device_short::DeviceShort;
|
||||||
pub use device_state::DeviceState;
|
pub use device_state::DeviceState;
|
||||||
|
#[cfg(feature = "mdns")]
|
||||||
pub use mdns_services::MDNSServices;
|
pub use mdns_services::MDNSServices;
|
||||||
pub use server_status::{MDNSBackend, ServerStatus};
|
pub use server_status::{MDNSBackend, ServerStatus};
|
||||||
pub use wait_for_device::{WaitForDeviceState, WaitForDeviceTransport};
|
pub use wait_for_device::{WaitForDeviceState, WaitForDeviceTransport};
|
||||||
|
|||||||
Reference in New Issue
Block a user