mirror of
https://github.com/Tencent/BrowserSkill.git
synced 2026-09-10 13:01:23 +08:00
Initial public release
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
//! `bsk browsers` — list connected extension clients (M4).
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Context;
|
||||
use bsk_protocol::Method;
|
||||
use bsk_protocol::system::BrowserStatusEntry;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::cli::ensure_daemon::ensure_daemon;
|
||||
use crate::cli::error::{CliError, Format};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ListReply {
|
||||
browsers: Vec<BrowserStatusEntry>,
|
||||
}
|
||||
|
||||
pub fn dispatch(format: Format) -> Result<(), CliError> {
|
||||
let info = ensure_daemon().context("ensure daemon is running")?;
|
||||
run_list(info.sock_path, format)
|
||||
}
|
||||
|
||||
fn run_list(sock: PathBuf, format: Format) -> Result<(), CliError> {
|
||||
let reply: ListReply = call(sock, Duration::from_secs(5))?;
|
||||
match format {
|
||||
Format::Json => {
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&reply.browsers)
|
||||
.map_err(|e| CliError::Local(anyhow::anyhow!(e)))?
|
||||
);
|
||||
}
|
||||
Format::Human => {
|
||||
if reply.browsers.is_empty() {
|
||||
println!("(no browsers connected)");
|
||||
return Ok(());
|
||||
}
|
||||
let rows: Vec<[String; 5]> = reply
|
||||
.browsers
|
||||
.iter()
|
||||
.map(|b| {
|
||||
[
|
||||
b.instance_id.clone(),
|
||||
format!("{} {}", b.browser_name, b.browser_version),
|
||||
b.extension_version.clone(),
|
||||
if b.label.is_empty() {
|
||||
"-".into()
|
||||
} else {
|
||||
b.label.clone()
|
||||
},
|
||||
b.session_count.to_string(),
|
||||
]
|
||||
})
|
||||
.collect();
|
||||
let headers = ["INSTANCE", "BROWSER", "EXT", "LABEL", "SESSIONS"];
|
||||
let widths: [usize; 5] = std::array::from_fn(|i| {
|
||||
rows.iter()
|
||||
.map(|r| r[i].len())
|
||||
.max()
|
||||
.unwrap_or(0)
|
||||
.max(headers[i].len())
|
||||
});
|
||||
println!(
|
||||
"{:<w0$} {:<w1$} {:<w2$} {:<w3$} {}",
|
||||
headers[0],
|
||||
headers[1],
|
||||
headers[2],
|
||||
headers[3],
|
||||
headers[4],
|
||||
w0 = widths[0],
|
||||
w1 = widths[1],
|
||||
w2 = widths[2],
|
||||
w3 = widths[3],
|
||||
);
|
||||
for r in &rows {
|
||||
println!(
|
||||
"{:<w0$} {:<w1$} {:<w2$} {:<w3$} {}",
|
||||
r[0],
|
||||
r[1],
|
||||
r[2],
|
||||
r[3],
|
||||
r[4],
|
||||
w0 = widths[0],
|
||||
w1 = widths[1],
|
||||
w2 = widths[2],
|
||||
w3 = widths[3],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn call(sock: PathBuf, timeout: Duration) -> Result<ListReply, CliError> {
|
||||
let rt = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.context("build tokio runtime for browser.list RPC")
|
||||
.map_err(CliError::Local)?;
|
||||
rt.block_on(async move {
|
||||
let mut client = crate::ipc_client::IpcClient::connect(sock).await?;
|
||||
let outcome = client
|
||||
.call::<(), ListReply>("browser-list-1", Method::BrowserList, None, timeout)
|
||||
.await?;
|
||||
outcome.map_err(CliError::from_rpc)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user