demo: learn to connect to a specific VM

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2021-08-21 00:54:27 +04:00
parent fe6906e996
commit 06c8554023
4 changed files with 97 additions and 10 deletions

View File

@ -1,10 +1,17 @@
use futures::stream::{self, StreamExt};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::convert::TryInto;
use zbus::azync::Connection;
use zbus::fdo;
use zbus::fdo::ManagedObjects;
use zbus::names::BusName;
use zbus::names::OwnedUniqueName;
use zbus::names::UniqueName;
use zbus::names::WellKnownName;
use zvariant::OwnedObjectPath;
use crate::{Audio, Chardev, Clipboard, Result, UsbRedir};
use crate::{AsyncVMProxy, Audio, Chardev, Clipboard, Error, Result, UsbRedir};
pub struct Display {
conn: Connection,
@ -12,9 +19,36 @@ pub struct Display {
}
impl Display {
pub async fn new(conn: &Connection) -> Result<Self> {
let objects = zbus::fdo::AsyncObjectManagerProxy::builder(&conn)
.destination("org.qemu")?
pub async fn by_name(conn: &Connection) -> Result<HashMap<String, OwnedUniqueName>> {
let mut hm = HashMap::new();
let list = fdo::AsyncDBusProxy::new(conn)
.await?
.list_queued_owners(WellKnownName::from_str_unchecked("org.qemu"))
.await?;
for dest in list.into_iter() {
let name = AsyncVMProxy::builder(conn)
.destination(UniqueName::from(&dest))?
.build()
.await?
.name()
.await?;
hm.insert(name, dest);
}
Ok(hm)
}
pub async fn new<'d, D>(conn: &Connection, dest: Option<D>) -> Result<Self>
where
D: TryInto<BusName<'d>>,
D::Error: Into<Error>,
{
let dest: BusName = if let Some(dest) = dest {
dest.try_into().map_err(Into::into)?
} else {
"org.qemu".try_into().unwrap()
};
let objects = fdo::AsyncObjectManagerProxy::builder(&conn)
.destination(dest)?
.path("/org/qemu/Display1")?
.build()
.await?

View File

@ -1,5 +1,6 @@
use usbredirhost::rusb;
use std::convert::Infallible;
use std::error;
use std::fmt;
use std::io;
@ -61,6 +62,12 @@ impl From<zvariant::Error> for Error {
}
}
impl From<zbus::names::Error> for Error {
fn from(e: zbus::names::Error) -> Self {
Error::Zbus(e.into())
}
}
impl From<rusb::Error> for Error {
fn from(e: rusb::Error) -> Self {
Error::Rusb(e)
@ -73,4 +80,10 @@ impl From<usbredirhost::Error> for Error {
}
}
impl From<Infallible> for Error {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
pub type Result<T> = std::result::Result<T, Error>;

View File

@ -252,11 +252,7 @@ impl UsbRedir {
}
// We should do better and watch for owner properties changes, but this would require tasks
let _ = inner
.channel
.0
.broadcast(Event::NFreeChannels(nfree))
.await;
let _ = inner.channel.0.broadcast(Event::NFreeChannels(nfree)).await;
Ok(state)
}

View File

@ -27,6 +27,37 @@ struct App {
impl App {
fn new() -> Self {
let app = gtk::Application::new(Some("org.qemu.rdw.demo"), ApplicationFlags::NON_UNIQUE);
app.add_main_option(
&glib::OPTION_REMAINING,
glib::Char(0),
glib::OptionFlags::NONE,
glib::OptionArg::StringArray,
"VM-NAME",
Some("VM name"),
);
app.add_main_option(
"version",
glib::Char(0),
glib::OptionFlags::NONE,
glib::OptionArg::None,
"Show program version",
None,
);
let opt_name: Arc<RefCell<Option<String>>> = Default::default();
let name = opt_name.clone();
app.connect_handle_local_options(move |_, opt| {
if opt.lookup_value("version", None).is_some() {
println!("Version: {}", env!("CARGO_PKG_VERSION"));
return 0;
}
name.replace(
opt.lookup_value(&glib::OPTION_REMAINING, None)
.and_then(|args| args.child_value(0).get::<String>()),
);
-1
});
let conn = Connection::session()
.expect("Failed to connect to DBus")
.into();
@ -53,8 +84,21 @@ impl App {
window.set_application(Some(app));
let app_clone = app_clone.clone();
let opt_name = opt_name.clone();
MainContext::default().spawn_local(async move {
let display = Display::new(app_clone.connection()).await.unwrap();
let name = if let Some(name) = opt_name.borrow().as_ref() {
let list = Display::by_name(app_clone.connection()).await.unwrap();
Some(
list.get(name)
.expect(&format!("Can't find VM name: {}", name))
.clone(),
)
} else {
None
};
let display = Display::new(app_clone.connection(), name.as_ref())
.await
.unwrap();
let console = Console::new(app_clone.connection(), 0)
.await