add ubus api for 'send', 'call', 'list' and 'wait_for'
This commit is contained in:
parent
044d774ef0
commit
a652a7ac07
294
Cargo.lock
generated
294
Cargo.lock
generated
@ -31,7 +31,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cee8cf1202a4f94d31837f1902ab0a75c77b65bf59719e093703abe83efd74ec"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -44,7 +44,7 @@ dependencies = [
|
||||
"accesskit_consumer",
|
||||
"objc2",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -58,7 +58,7 @@ dependencies = [
|
||||
"async-channel",
|
||||
"atspi",
|
||||
"futures-lite",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"serde",
|
||||
"zbus",
|
||||
]
|
||||
@ -73,7 +73,7 @@ dependencies = [
|
||||
"accesskit_consumer",
|
||||
"arrayvec",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"paste",
|
||||
"windows",
|
||||
]
|
||||
@ -88,7 +88,7 @@ dependencies = [
|
||||
"accesskit_macos",
|
||||
"accesskit_unix",
|
||||
"accesskit_windows",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"winit",
|
||||
]
|
||||
|
||||
@ -160,7 +160,7 @@ dependencies = [
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"thiserror",
|
||||
"winapi",
|
||||
"x11rb",
|
||||
@ -254,6 +254,36 @@ dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-net"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"autocfg",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6381ead98388605d0d9ff86371043b5aa922a3905824244de40dc263a14fcba4"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"autocfg",
|
||||
"blocking",
|
||||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"libc",
|
||||
"signal-hook",
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.0.4"
|
||||
@ -265,6 +295,19 @@ dependencies = [
|
||||
"syn 2.0.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-ssh2-lite"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "068cabec74fe85e7a689c96fe3eecd5f3bce99d7358beeecd7d690372bc4de0e"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-trait",
|
||||
"futures-util",
|
||||
"libssh2-sys",
|
||||
"ssh2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.4.0"
|
||||
@ -785,7 +828,7 @@ dependencies = [
|
||||
"ecolor",
|
||||
"emath",
|
||||
"nohash-hasher",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -906,6 +949,17 @@ dependencies = [
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.27"
|
||||
@ -926,6 +980,7 @@ checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
@ -1058,6 +1113,15 @@ version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
@ -1108,11 +1172,17 @@ version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"hermit-abi 0.3.1",
|
||||
"libc",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.21.1"
|
||||
@ -1159,6 +1229,29 @@ version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||
|
||||
[[package]]
|
||||
name = "lazy-regex"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff63c423c68ea6814b7da9e88ce585f793c87ddd9e78f646970891769c8235d4"
|
||||
dependencies = [
|
||||
"lazy-regex-proc_macros",
|
||||
"once_cell",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy-regex-proc_macros"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8edfc11b8f56ce85e207e62ea21557cfa09bb24a8f6b04ae181b086ff8611c22"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@ -1181,6 +1274,32 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libssh2-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.1.4"
|
||||
@ -1365,6 +1484,16 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||
dependencies = [
|
||||
"hermit-abi 0.2.6",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.11"
|
||||
@ -1447,6 +1576,19 @@ version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "666416d899cf077260dac8698d60a60b435a46d57e82acb1be3d0dad87284e5b"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.43"
|
||||
@ -1484,6 +1626,17 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
@ -1491,7 +1644,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
"parking_lot_core 0.9.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1709,6 +1876,12 @@ dependencies = [
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@ -1775,6 +1948,17 @@ dependencies = [
|
||||
"syn 2.0.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.12"
|
||||
@ -1806,6 +1990,31 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-escape"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.8"
|
||||
@ -1859,6 +2068,23 @@ dependencies = [
|
||||
"wayland-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smol"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
"async-fs",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-net",
|
||||
"async-process",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.9"
|
||||
@ -1869,6 +2095,18 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ssh2"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7fe461910559f6d5604c3731d00d2aafc4a83d1665922e280f42f9a168d5455"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
"libssh2-sys",
|
||||
"parking_lot 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
@ -1982,6 +2220,30 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.3"
|
||||
@ -2065,11 +2327,19 @@ name = "ubusman"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-ssh2-lite",
|
||||
"directories-next",
|
||||
"eframe",
|
||||
"egui",
|
||||
"hex",
|
||||
"lazy-regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shell-escape",
|
||||
"smol",
|
||||
"ssh2",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"toml",
|
||||
]
|
||||
|
||||
@ -2115,6 +2385,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
|
@ -7,9 +7,17 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.70"
|
||||
async-ssh2-lite = { version = "0.4.5", features = ["async-io"] }
|
||||
directories-next = "2.0.0"
|
||||
eframe = "0.21.3"
|
||||
egui = "0.21.0"
|
||||
hex = "0.4.3"
|
||||
lazy-regex = "2.5.0"
|
||||
serde = { version = "1.0.158", features = ["derive"] }
|
||||
serde_json = "1.0.94"
|
||||
shell-escape = "0.1.5"
|
||||
smol = "1.3.0"
|
||||
ssh2 = "0.9.4"
|
||||
thiserror = "1.0.40"
|
||||
tokio = { version = "1.26.0", features = ["macros", "rt-multi-thread"] }
|
||||
toml = "0.7.3"
|
||||
|
40
src/main.rs
40
src/main.rs
@ -1,9 +1,42 @@
|
||||
use std::net::ToSocketAddrs;
|
||||
|
||||
#[cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use anyhow::Result;
|
||||
use smol::Async;
|
||||
use async_ssh2_lite::{AsyncSession, AsyncSessionStream};
|
||||
use app::App;
|
||||
|
||||
mod app;
|
||||
use crate::ubus::Ubus;
|
||||
|
||||
fn main() -> eframe::Result<()> {
|
||||
mod app;
|
||||
mod ubus;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let address = "172.24.224.1:22";
|
||||
let username = "root";
|
||||
let password = "admin01";
|
||||
|
||||
let mut session = AsyncSession::<async_ssh2_lite::AsyncIoTcpStream>::connect(
|
||||
address.to_socket_addrs()?.next().unwrap(),
|
||||
None,
|
||||
).await?;
|
||||
|
||||
session.handshake().await?;
|
||||
session.userauth_password(username, password).await?;
|
||||
|
||||
let ubus = Ubus::new(session);
|
||||
// dbg!(ubus.call(
|
||||
// "container",
|
||||
// "get_features",
|
||||
// None
|
||||
// ).await?
|
||||
// );
|
||||
|
||||
dbg!(ubus.wait_for(&vec!["network"]).await?);
|
||||
|
||||
/*
|
||||
let mut native_options = eframe::NativeOptions::default();
|
||||
native_options.decorated = true;
|
||||
native_options.resizable = true;
|
||||
@ -17,5 +50,8 @@ fn main() -> eframe::Result<()> {
|
||||
Box::new(app)
|
||||
})
|
||||
)
|
||||
*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
220
src/ubus.rs
Normal file
220
src/ubus.rs
Normal file
@ -0,0 +1,220 @@
|
||||
use std::{io::Read, borrow::Cow, net::TcpStream};
|
||||
|
||||
use async_ssh2_lite::AsyncSession;
|
||||
use lazy_regex::regex_captures;
|
||||
use serde_json::Value;
|
||||
use shell_escape::unix::escape;
|
||||
use hex::FromHex;
|
||||
use anyhow::{Result, bail, anyhow};
|
||||
use smol::{Async, io::AsyncReadExt};
|
||||
use thiserror::Error;
|
||||
|
||||
pub struct Ubus {
|
||||
session: AsyncSession<Async<TcpStream>>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UbusParamType {
|
||||
Unknown,
|
||||
Integer,
|
||||
Boolean,
|
||||
Table,
|
||||
String,
|
||||
Array,
|
||||
Double
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum UbusError {
|
||||
#[error("Invalid command")]
|
||||
InvalidCommand,
|
||||
#[error("Invalid argument")]
|
||||
InvalidArgument,
|
||||
#[error("Method not found")]
|
||||
MethodNotFound,
|
||||
#[error("Not found")]
|
||||
NotFound,
|
||||
#[error("No response")]
|
||||
NoData,
|
||||
#[error("Permission denied")]
|
||||
PermissionDenied,
|
||||
#[error("Request timed out")]
|
||||
Timeout,
|
||||
#[error("Operation not supported")]
|
||||
NotSupported,
|
||||
#[error("Unknown error")]
|
||||
UnknownError,
|
||||
#[error("Connection failed")]
|
||||
ConnectionFailed,
|
||||
#[error("Out of memory")]
|
||||
NoMemory,
|
||||
#[error("Parsing message data failed")]
|
||||
ParseError,
|
||||
#[error("System error")]
|
||||
SystemError,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UbusObject {
|
||||
pub name: String,
|
||||
pub id: u32,
|
||||
pub methods: Vec<(String, Vec<(String, UbusParamType)>)>
|
||||
}
|
||||
|
||||
fn parse_parameter_type(param: &str) -> Option<UbusParamType> {
|
||||
use UbusParamType::*;
|
||||
match param {
|
||||
"String" => Some(String),
|
||||
"Boolean" => Some(Boolean),
|
||||
"Integer" => Some(Integer),
|
||||
"Double" => Some(Double),
|
||||
"Table" => Some(Table),
|
||||
"Array" => Some(Array),
|
||||
"(unknown)" => Some(Unknown),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_error_code(code: i32) -> Option<UbusError> {
|
||||
use UbusError::*;
|
||||
|
||||
match code {
|
||||
0 => None,
|
||||
1 => Some(InvalidCommand),
|
||||
2 => Some(InvalidArgument),
|
||||
3 => Some(MethodNotFound),
|
||||
4 => Some(NotFound),
|
||||
5 => Some(NoData),
|
||||
6 => Some(PermissionDenied),
|
||||
7 => Some(Timeout),
|
||||
8 => Some(NotSupported),
|
||||
9 => Some(UnknownError),
|
||||
10 => Some(ConnectionFailed),
|
||||
11 => Some(NoMemory),
|
||||
12 => Some(ParseError),
|
||||
13 => Some(SystemError),
|
||||
_ => Some(UnknownError)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_hex_id(id: &str) -> Result<u32> {
|
||||
let [byte1, byte2, byte3, byte4] = <[u8; 4]>::from_hex(id)?;
|
||||
let byte1 = (byte1 as u32) << 24;
|
||||
let byte2 = (byte2 as u32) << 16;
|
||||
let byte3 = (byte3 as u32) << 8;
|
||||
let byte4 = (byte4 as u32) << 0;
|
||||
|
||||
return Ok(byte1 + byte2 + byte3 + byte4);
|
||||
}
|
||||
|
||||
fn escape_json(json: &Value) -> String {
|
||||
escape(Cow::from(json.to_string())).into()
|
||||
}
|
||||
|
||||
impl Ubus {
|
||||
pub fn new(session: AsyncSession<Async<TcpStream>>) -> Ubus {
|
||||
Ubus {
|
||||
session
|
||||
}
|
||||
}
|
||||
|
||||
async fn exec_cmd(&self, cmd: &str) -> Result<String> {
|
||||
let mut channel = self.session.channel_session().await?;
|
||||
channel.exec(cmd).await?;
|
||||
channel.close().await?;
|
||||
if let Some(err) = parse_error_code(channel.exit_status()?) {
|
||||
return Err(err.into())
|
||||
}
|
||||
|
||||
let mut output = String::new();
|
||||
channel.read_to_string(&mut output).await?;
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub async fn list(self, path: Option<&str>) -> Result<Vec<String>> {
|
||||
let output = match path {
|
||||
Some(path) => self.exec_cmd(&format!("ubus list {}", path)).await?,
|
||||
None => self.exec_cmd("ubus list").await?,
|
||||
};
|
||||
Ok(output.lines().map(ToOwned::to_owned).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
pub async fn list_verbose(self, path: Option<&str>) -> Result<Vec<UbusObject>> {
|
||||
let output = match path {
|
||||
Some(path) => self.exec_cmd(&format!("ubus -v list {}", path)).await?,
|
||||
None => self.exec_cmd("ubus -v list").await?,
|
||||
};
|
||||
|
||||
let mut cur_name = None;
|
||||
let mut cur_id = None;
|
||||
let mut cur_methods = vec![];
|
||||
|
||||
let mut objects = vec![];
|
||||
for line in output.lines() {
|
||||
if let Some((_, name, id)) = regex_captures!(r"^'([\w.-]+)' @([0-9a-zA-Z]+)$", line) {
|
||||
if cur_name.is_some() && cur_id.is_some() {
|
||||
objects.push(UbusObject {
|
||||
id: cur_id.unwrap(),
|
||||
name: cur_name.unwrap(),
|
||||
methods: cur_methods
|
||||
});
|
||||
cur_methods = vec![];
|
||||
}
|
||||
|
||||
cur_name = Some(name.into());
|
||||
cur_id = Some(parse_hex_id(id)?);
|
||||
} else if let Some((_, name, params_body)) = regex_captures!(r#"^\s+"([\w-]+)":\{(.*)}$"#, line) {
|
||||
let mut params = vec![];
|
||||
if !params_body.is_empty() {
|
||||
for param in params_body.split(",") {
|
||||
let (_, name, param_type_name) = regex_captures!(r#"^"([\w-]+)":"(\w+)"$"#, param)
|
||||
.ok_or(anyhow!("Failed to parse parameter '{}' in line '{}'", param, line))?;
|
||||
|
||||
let param_type = parse_parameter_type(param_type_name)
|
||||
.ok_or(anyhow!("Unknown parameter type '{}'", param_type_name))?;
|
||||
|
||||
params.push((name.into(), param_type));
|
||||
}
|
||||
}
|
||||
cur_methods.push((name.into(), params));
|
||||
} else {
|
||||
bail!("Failed to parse line '{}'", line);
|
||||
}
|
||||
}
|
||||
Ok(objects)
|
||||
}
|
||||
|
||||
pub async fn call(self, path: &str, method: &str, message: Option<&Value>) -> Result<Value> {
|
||||
let cmd = match message {
|
||||
Some(msg) => format!("ubus call {} {} {}", path, method, escape_json(msg)),
|
||||
None => format!("ubus call {} {}", path, method),
|
||||
};
|
||||
|
||||
let output = self.exec_cmd(&cmd).await?;
|
||||
let value = serde_json::from_str::<Value>(&output)?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub async fn send(self, event_type: &str, message: Option<&Value>) -> Result<()> {
|
||||
let cmd = match message {
|
||||
Some(msg) => format!("ubus send {} {}", event_type, escape_json(msg)),
|
||||
None => format!("ubus send {}", event_type),
|
||||
};
|
||||
|
||||
self.exec_cmd(&cmd).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn wait_for(self, objects: &[&str]) -> Result<()> {
|
||||
if objects.len() < 1 {
|
||||
bail!("At least 1 object is required")
|
||||
}
|
||||
let cmd = format!("ubus wait_for {}", objects.join(" "));
|
||||
let mut channel = self.session.channel_session().await?;
|
||||
channel.exec(&cmd).await?;
|
||||
channel.close().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user