feat: support wasm build for adb_client
This commit is contained in:
@@ -18,26 +18,26 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
default = []
|
||||
mdns = ["dep:mdns-sd"]
|
||||
rusb = ["dep:rsa", "dep:rusb"]
|
||||
webusb = ["dep:webusb-web", "dep:rsa"]
|
||||
|
||||
[dependencies]
|
||||
base64 = { version = "0.22.1" }
|
||||
bincode = { version = "1.3.3" }
|
||||
byteorder = { version = "1.5.0" }
|
||||
chrono = { version = "0.4.42", default-features = false, features = ["std"] }
|
||||
homedir = { version = "=0.3.4" }
|
||||
image = { version = "0.25.8", default-features = false }
|
||||
log = { version = "0.4.28" }
|
||||
num-bigint = { version = "0.8.4", package = "num-bigint-dig" }
|
||||
num-traits = { version = "0.2.19" }
|
||||
quick-protobuf = { version = "0.8.1" }
|
||||
rand = { version = "0.9.2" }
|
||||
rand = { version = "0.8.5" }
|
||||
rcgen = { version = "0.13.2", default-features = false, features = [
|
||||
"aws_lc_rs",
|
||||
"pem",
|
||||
"ring"
|
||||
] }
|
||||
regex = { version = "1.12.2", features = ["perf", "std", "unicode"] }
|
||||
rustls = { version = "0.23.33" }
|
||||
rustls-pki-types = { version = "1.12.0" }
|
||||
rustls = { version = "0.23.33", default-features = false, features = ["logging", "ring", "std", "tls12"] }
|
||||
rustls-pki-types = { version = "1.12.0", features = ["web"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_repr = { version = "0.1.20" }
|
||||
sha1 = { version = "0.10.6", features = ["oid"] }
|
||||
@@ -54,6 +54,12 @@ mdns-sd = { version = "0.13.11", default-features = false, features = [
|
||||
rsa = { version = "0.9.7", optional = true }
|
||||
rusb = { version = "0.9.4", features = ["vendored"], optional = true }
|
||||
#########
|
||||
#########
|
||||
# webusb dependencies
|
||||
webusb-web = { version = "0.4.1", optional = true }
|
||||
getrandom = { version = "0.2.16", features = ["js"] }
|
||||
ring = { version = "0.17.14", features = ["wasm32_unknown_unknown_js"] }
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = { version = "1.0.100" }
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::{RebootType, Result};
|
||||
|
||||
/// Trait representing all features available on an ADB device, currently used by:
|
||||
/// - [`crate::server_device::ADBServerDevice`]
|
||||
/// - [`crate::usb::ADBUSBDevice`]
|
||||
/// - [`crate::usb::ADBRusbDevice`]
|
||||
/// - [`crate::tcp::ADBTcpDevice`]
|
||||
pub trait ADBDeviceExt {
|
||||
/// Runs command in a shell on the device, and write its output and error streams into output.
|
||||
|
||||
@@ -4,8 +4,6 @@ use std::{
|
||||
net::{SocketAddrV4, TcpStream},
|
||||
};
|
||||
|
||||
use homedir::my_home;
|
||||
|
||||
use crate::{
|
||||
Result, RustADBError, adb_transport::ADBTransport, emulator::models::ADBEmulatorCommand,
|
||||
};
|
||||
@@ -37,7 +35,7 @@ impl TCPEmulatorTransport {
|
||||
|
||||
/// Return authentication token stored in `$HOME/.emulator_console_auth_token`
|
||||
pub fn get_authentication_token(&mut self) -> Result<String> {
|
||||
let Some(home) = my_home()? else {
|
||||
let Some(home) = std::env::home_dir() else {
|
||||
return Err(RustADBError::NoHomeDirectory);
|
||||
};
|
||||
|
||||
|
||||
@@ -63,9 +63,6 @@ pub enum RustADBError {
|
||||
/// Unimplemented framebuffer image version
|
||||
#[error("Unimplemented framebuffer image version: {0}")]
|
||||
UnimplementedFramebufferImageVersion(u32),
|
||||
/// An error occurred while getting user's home directory
|
||||
#[error(transparent)]
|
||||
HomeError(#[from] homedir::GetHomeError),
|
||||
/// Cannot get home directory
|
||||
#[error("Cannot get home directory")]
|
||||
NoHomeDirectory,
|
||||
@@ -90,8 +87,8 @@ pub enum RustADBError {
|
||||
#[error(transparent)]
|
||||
Base64EncodeError(#[from] base64::EncodeSliceError),
|
||||
/// An error occurred with RSA engine
|
||||
#[cfg(feature = "rusb")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rusb")))]
|
||||
#[cfg(any(feature = "rusb", feature = "webusb"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "rusb", feature = "webusb"))))]
|
||||
#[error(transparent)]
|
||||
RSAError(#[from] rsa::errors::Error),
|
||||
/// Cannot convert given data from slice
|
||||
@@ -101,8 +98,8 @@ pub enum RustADBError {
|
||||
#[error("wrong file extension: {0}")]
|
||||
WrongFileExtension(String),
|
||||
/// An error occurred with PKCS8 data
|
||||
#[cfg(feature = "rusb")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rusb")))]
|
||||
#[cfg(any(feature = "rusb", feature = "webusb"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "rusb", feature = "webusb"))))]
|
||||
#[error("error with pkcs8: {0}")]
|
||||
RsaPkcs8Error(#[from] rsa::pkcs8::Error),
|
||||
/// Error during certificate generation
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use rand::Rng;
|
||||
use std::io::{Cursor, Read, Seek};
|
||||
|
||||
use crate::{
|
||||
@@ -219,11 +218,9 @@ impl<T: ADBMessageTransport> ADBMessageDevice<T> {
|
||||
}
|
||||
|
||||
pub(crate) fn open_session(&mut self, data: &[u8]) -> Result<ADBTransportMessage> {
|
||||
let mut rng = rand::rng();
|
||||
|
||||
let message = ADBTransportMessage::new(
|
||||
MessageCommand::Open,
|
||||
rng.random(), // Our 'local-id'
|
||||
rand::random::<u32>(), // Our 'local-id'
|
||||
0,
|
||||
data,
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@ pub struct ADBRusbDevice {
|
||||
}
|
||||
|
||||
impl ADBRusbDevice {
|
||||
/// Instantiate a new [`ADBRusb`]
|
||||
/// Instantiate a new [`ADBRusbDevice`]
|
||||
pub fn new(vendor_id: u16, product_id: u16) -> Result<Self> {
|
||||
Self::new_with_custom_private_key(vendor_id, product_id, get_default_adb_key_path()?)
|
||||
}
|
||||
|
||||
69
adb_client/src/message_devices/usb/adb_webusb_device.rs
Normal file
69
adb_client/src/message_devices/usb/adb_webusb_device.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use std::{
|
||||
io::{Read, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ADBDeviceExt, Result,
|
||||
usb::{WebUsbTransport, adb_usb_device::ADBUSBDevice},
|
||||
};
|
||||
|
||||
/// Implement Android USB device reachable over wired USB
|
||||
#[derive(Debug)]
|
||||
pub struct ADBWebUsbDevice {
|
||||
inner: ADBUSBDevice<WebUsbTransport>,
|
||||
}
|
||||
|
||||
impl ADBWebUsbDevice {
|
||||
/// Instantiate a new [`ADBRusb`]
|
||||
pub fn new(_vendor_id: u16, _product_id: u16) -> Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ADBDeviceExt for ADBWebUsbDevice {
|
||||
#[inline]
|
||||
fn shell_command(&mut self, command: &[&str], output: &mut dyn Write) -> Result<()> {
|
||||
self.inner.shell_command(command, output)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shell<'a>(&mut self, reader: &mut dyn Read, writer: Box<dyn Write + Send>) -> Result<()> {
|
||||
self.inner.shell(reader, writer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn stat(&mut self, remote_path: &str) -> Result<crate::AdbStatResponse> {
|
||||
self.inner.stat(remote_path)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pull(&mut self, source: &dyn AsRef<str>, output: &mut dyn Write) -> Result<()> {
|
||||
self.inner.pull(source, output)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push(&mut self, stream: &mut dyn Read, path: &dyn AsRef<str>) -> Result<()> {
|
||||
self.inner.push(stream, path)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reboot(&mut self, reboot_type: crate::RebootType) -> Result<()> {
|
||||
self.inner.reboot(reboot_type)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn install(&mut self, apk_path: &dyn AsRef<Path>) -> Result<()> {
|
||||
self.inner.install(apk_path)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn uninstall(&mut self, package: &str) -> Result<()> {
|
||||
self.inner.uninstall(package)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn framebuffer_inner(&mut self) -> Result<image::ImageBuffer<image::Rgba<u8>, Vec<u8>>> {
|
||||
self.inner.framebuffer_inner()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
#[cfg(feature = "rusb")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rusb")))]
|
||||
pub mod rusb_transport;
|
||||
|
||||
#[cfg(feature = "webusb")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "webusb")))]
|
||||
pub mod webusb_transport;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{
|
||||
Result,
|
||||
adb_transport::ADBTransport,
|
||||
message_devices::{
|
||||
adb_message_transport::ADBMessageTransport, adb_transport_message::ADBTransportMessage,
|
||||
},
|
||||
};
|
||||
|
||||
/// Transport running on USB using `webusb` as a backend.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WebUsbTransport {}
|
||||
|
||||
impl WebUsbTransport {
|
||||
/// Instantiate a new [`WebUsbTransport`].
|
||||
/// Only the first device with given vendor_id and product_id is returned.
|
||||
pub fn new() -> Self {
|
||||
WebUsbTransport {}
|
||||
}
|
||||
}
|
||||
|
||||
impl ADBTransport for WebUsbTransport {
|
||||
fn connect(&mut self) -> crate::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn disconnect(&mut self) -> crate::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ADBMessageTransport for WebUsbTransport {
|
||||
fn read_message_with_timeout(
|
||||
&mut self,
|
||||
_read_timeout: Duration,
|
||||
) -> Result<ADBTransportMessage> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn write_message_with_timeout(
|
||||
&mut self,
|
||||
message: ADBTransportMessage,
|
||||
write_timeout: std::time::Duration,
|
||||
) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -30,18 +30,11 @@ pub mod constants {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rusb")]
|
||||
mod adb_rsa_key;
|
||||
|
||||
// ###################################################
|
||||
// rusb specific modules
|
||||
#[cfg(feature = "rusb")]
|
||||
mod adb_rusb_device;
|
||||
|
||||
#[cfg(feature = "rusb")]
|
||||
mod adb_usb_device;
|
||||
|
||||
mod backends;
|
||||
mod utils;
|
||||
|
||||
// Device implementations
|
||||
#[cfg(feature = "rusb")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rusb")))]
|
||||
@@ -51,10 +44,36 @@ pub use adb_rusb_device::ADBRusbDevice;
|
||||
#[cfg(feature = "rusb")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rusb")))]
|
||||
pub use backends::rusb_transport::RusbTransport;
|
||||
// ###################################################
|
||||
|
||||
// ###################################################
|
||||
// webusb specific modules
|
||||
#[cfg(feature = "webusb")]
|
||||
mod adb_webusb_device;
|
||||
|
||||
// Device implementations
|
||||
#[cfg(feature = "webusb")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "webusb")))]
|
||||
pub use adb_webusb_device::ADBWebUsbDevice;
|
||||
|
||||
// Transport implementations
|
||||
#[cfg(feature = "webusb")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "webusb")))]
|
||||
pub use backends::webusb_transport::WebUsbTransport;
|
||||
// ###################################################
|
||||
|
||||
mod backends;
|
||||
mod utils;
|
||||
|
||||
#[cfg(any(feature = "rusb", feature = "webusb"))]
|
||||
mod adb_rsa_key;
|
||||
|
||||
#[cfg(any(feature = "rusb", feature = "webusb"))]
|
||||
mod adb_usb_device;
|
||||
|
||||
// Utility functions
|
||||
#[cfg(feature = "rusb")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rusb")))]
|
||||
#[cfg(any(feature = "rusb", feature = "webusb"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "rusb", feature = "webusb"))))]
|
||||
pub use utils::read_adb_private_key;
|
||||
|
||||
#[cfg(feature = "rusb")]
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::{Result, RustADBError};
|
||||
use std::fs::read_to_string;
|
||||
use std::path::Path;
|
||||
|
||||
#[cfg(feature = "rusb")]
|
||||
use crate::usb::adb_rsa_key::ADBRsaKey;
|
||||
|
||||
#[cfg(feature = "rusb")]
|
||||
@@ -21,7 +20,6 @@ use crate::usb::constants::class_codes::{
|
||||
///
|
||||
/// Returns `Ok(None)` if the file doesn't exist, `Ok(Some(key))` if the key was successfully loaded,
|
||||
/// or an error if there was a problem reading the file.
|
||||
#[cfg(feature = "rusb")]
|
||||
pub fn read_adb_private_key<P: AsRef<Path>>(private_key_path: P) -> Result<Option<ADBRsaKey>> {
|
||||
// Try to read the private key file from given path
|
||||
// If the file is not found, return None
|
||||
|
||||
@@ -21,9 +21,7 @@ pub fn check_extension_is_apk<P: AsRef<Path>>(path: P) -> Result<()> {
|
||||
}
|
||||
|
||||
pub fn get_default_adb_key_path() -> Result<PathBuf> {
|
||||
homedir::my_home()
|
||||
.ok()
|
||||
.flatten()
|
||||
std::env::home_dir()
|
||||
.map(|home| home.join(".android").join("adbkey"))
|
||||
.ok_or(RustADBError::NoHomeDirectory)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user