Compare commits
No commits in common. "main" and "packaging-simplification" have entirely different histories.
main
...
packaging-
10 changed files with 66 additions and 545 deletions
89
Cargo.lock
generated
89
Cargo.lock
generated
|
|
@ -142,8 +142,8 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
|||
|
||||
[[package]]
|
||||
name = "busd"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/valpackett/busd?branch=val%2Fmsksqvsqqrxm#7084025107e02600043856c56fd178730526daad"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/valpackett/busd?branch=val%2Fmsksqvsqqrxm#25736c855284b13371f0be2ef38f16af8f73bda1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
|
|
@ -151,8 +151,8 @@ dependencies = [
|
|||
"event-listener",
|
||||
"fastrand",
|
||||
"futures-util",
|
||||
"nix 0.30.1",
|
||||
"quick-xml",
|
||||
"rustix",
|
||||
"serde",
|
||||
"tokio",
|
||||
"tracing",
|
||||
|
|
@ -641,9 +641,9 @@ checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
|||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.11.0"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "listenfd"
|
||||
|
|
@ -726,6 +726,19 @@ dependencies = [
|
|||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
|
|
@ -858,9 +871,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.39.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2e3bf4aa9d243beeb01a7b3bc30b77cfe2c44e24ec02d751a7104a53c2c49a1"
|
||||
checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
|
|
@ -927,15 +940,15 @@ checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.3"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1309,9 +1322,7 @@ version = "1.17.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
|
|
@ -1328,7 +1339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4e8b4d00e672f147fc86a09738fadb1445bd1c0a40542378dfb82909deeee688"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"nix",
|
||||
"nix 0.29.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1426,12 +1437,6 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
|
@ -1459,15 +1464,6 @@ dependencies = [
|
|||
"windows-targets 0.53.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
|
|
@ -1656,9 +1652,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "5.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc"
|
||||
version = "5.9.0"
|
||||
source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-recursion",
|
||||
|
|
@ -1668,17 +1663,16 @@ dependencies = [
|
|||
"futures-core",
|
||||
"futures-lite",
|
||||
"hex",
|
||||
"libc",
|
||||
"nix 0.30.1",
|
||||
"ordered-stream",
|
||||
"rustix",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"tokio",
|
||||
"tokio-vsock",
|
||||
"tracing",
|
||||
"uds_windows",
|
||||
"uuid",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
"winnow",
|
||||
"zbus_macros",
|
||||
"zbus_names",
|
||||
|
|
@ -1687,9 +1681,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "5.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222"
|
||||
version = "5.9.0"
|
||||
source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
|
|
@ -1702,9 +1695,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zbus_names"
|
||||
version = "4.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f"
|
||||
version = "4.2.0"
|
||||
source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"winnow",
|
||||
|
|
@ -1787,9 +1779,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "5.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b"
|
||||
version = "5.6.0"
|
||||
source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
|
||||
dependencies = [
|
||||
"endi",
|
||||
"enumflags2",
|
||||
|
|
@ -1801,9 +1792,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zvariant_derive"
|
||||
version = "5.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c"
|
||||
version = "5.6.0"
|
||||
source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
|
|
@ -1814,9 +1804,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zvariant_utils"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9"
|
||||
version = "3.2.0"
|
||||
source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
|
|
@ -9,4 +9,6 @@ members = [
|
|||
[workspace.dependencies]
|
||||
sidebus-common = { path = "sidebus-common" }
|
||||
busd = { git = "https://github.com/valpackett/busd", branch = "val/msksqvsqqrxm", default-features = false }
|
||||
zbus = { version = "5.0", default-features = false, features = ["tokio", "tokio-vsock", "bus-impl", "p2p"] }
|
||||
zbus = { git = "https://github.com/dbus2/zbus", default-features = false, features = ["tokio", "tokio-vsock", "bus-impl", "p2p"] }
|
||||
# zbus git to match busd git
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@
|
|||
src = ./.;
|
||||
cargoLock.lockFile = ./Cargo.lock;
|
||||
cargoLock.outputHashes = {
|
||||
"busd-0.5.0" = "sha256-IZZ2MeEmUbzRrH6SUz0pnecMH4f8Mh54WdhI4q44YfI=";
|
||||
"zbus-5.9.0" = "sha256-uaHPHdmDWYy0jeKPd0/eCUupID2tswGHmEmscp6fCII=";
|
||||
"busd-0.4.0" = "sha256-hIvjt3v6AYc7URLFknXTmSc+NdxOlN/2RGXVsuoNgA4=";
|
||||
};
|
||||
buildAndTestSubdir = crate;
|
||||
env = buildEnvVars;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ mod vsock;
|
|||
|
||||
use bus::SharedHostedBus;
|
||||
use clap::Parser;
|
||||
use eyre::OptionExt;
|
||||
use futures::{TryFutureExt, stream::FuturesUnordered};
|
||||
use std::{path::PathBuf, sync::Arc, time::Duration};
|
||||
use tokio::{net::UnixListener, process::Command, sync::Mutex};
|
||||
|
|
@ -37,10 +36,6 @@ struct BrokerCli {
|
|||
#[clap(long, default_value = "/run/vm-doc-portal")]
|
||||
guest_mountpoint: PathBuf,
|
||||
|
||||
/// Mappings from guest paths to host paths for passthrough file systems (for file transfer), in guest=host format
|
||||
#[clap(long)]
|
||||
path_mapping: Vec<String>,
|
||||
|
||||
/// Vsock port number to listen on for the VM bus
|
||||
#[clap(long)]
|
||||
vsock_port: Option<u32>,
|
||||
|
|
@ -49,10 +44,6 @@ struct BrokerCli {
|
|||
#[clap(long)]
|
||||
unix_path: Option<PathBuf>,
|
||||
|
||||
/// Use ANONYMOUS auth to connect to the guest bus instead of EXTERNAL with the provided --guest-uid
|
||||
#[clap(long)]
|
||||
guest_bus_anonymous_auth: bool,
|
||||
|
||||
/// The user ID for the appvm user inside of the guest
|
||||
#[clap(long, default_value = "1337")]
|
||||
guest_uid: u32,
|
||||
|
|
@ -74,31 +65,11 @@ async fn new_hosted_bus() -> eyre::Result<(
|
|||
Ok((Arc::new(Mutex::new(bus)), guid, owner_stream))
|
||||
}
|
||||
|
||||
fn parse_path_mapping(s: &str) -> eyre::Result<(PathBuf, PathBuf)> {
|
||||
let mut split = s.split('=');
|
||||
let guest_path = PathBuf::from(split.next().ok_or_eyre("failed to split mapping")?);
|
||||
let host_path = PathBuf::from(split.next().ok_or_eyre("failed to split mapping")?);
|
||||
Ok((guest_path, host_path))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> eyre::Result<()> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let cli = BrokerCli::parse();
|
||||
let mut path_prefix_to_host: Vec<(PathBuf, PathBuf)> = cli
|
||||
.path_mapping
|
||||
.iter()
|
||||
.flat_map(|arg| match parse_path_mapping(arg) {
|
||||
Ok(mapping) => Some(mapping),
|
||||
Err(err) => {
|
||||
error!(?err, %arg, "could not parse path mapping");
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
path_prefix_to_host.sort_unstable_by_key(|(prefix, _)| -(prefix.as_os_str().len() as isize));
|
||||
debug!(?path_prefix_to_host, "parsed path mappings");
|
||||
|
||||
let (priv_bus, _, mut priv_lst) = new_hosted_bus().await?;
|
||||
|
||||
|
|
@ -173,28 +144,16 @@ async fn main() -> eyre::Result<()> {
|
|||
let priv_bus_conn = priv_bus.lock().await.connect_channel(false).await?;
|
||||
let host_session_conn = zbus::connection::Builder::session()?.build().await?;
|
||||
let file_chooser_imp = portal::file_chooser::FileChooser::new(
|
||||
&host_session_conn,
|
||||
&priv_bus_conn,
|
||||
cli.guest_mountpoint.clone(),
|
||||
)
|
||||
.await?;
|
||||
let file_transfer_imp = portal::file_transfer::FileTransfer::new(
|
||||
&host_session_conn,
|
||||
&priv_bus_conn,
|
||||
cli.guest_mountpoint,
|
||||
path_prefix_to_host,
|
||||
)
|
||||
.await?;
|
||||
let notification_imp = portal::notification::Notification::new(&host_session_conn).await?;
|
||||
let print_imp = portal::print::Print::new(&host_session_conn).await?;
|
||||
let settings_imp = portal::settings::Settings::new(&host_session_conn).await?;
|
||||
|
||||
async fn on_vm_bus_connected(
|
||||
vm_bus_conn: zbus::Connection,
|
||||
file_chooser: portal::file_chooser::FileChooser,
|
||||
file_transfer: portal::file_transfer::FileTransfer,
|
||||
notification: portal::notification::Notification,
|
||||
print: portal::print::Print,
|
||||
settings: portal::settings::Settings,
|
||||
) -> Result<(), eyre::Report> {
|
||||
if !vm_bus_conn
|
||||
|
|
@ -204,55 +163,6 @@ async fn main() -> eyre::Result<()> {
|
|||
{
|
||||
error!("org.freedesktop.portal.FileChooser already provided");
|
||||
};
|
||||
|
||||
if !vm_bus_conn
|
||||
.object_server()
|
||||
.at("/org/freedesktop/portal/documents", file_transfer)
|
||||
.await?
|
||||
{
|
||||
error!("org.freedesktop.portal.FileTransfer already provided");
|
||||
};
|
||||
let file_transfer_ref = vm_bus_conn
|
||||
.object_server()
|
||||
.interface::<_, portal::file_transfer::FileTransfer>(
|
||||
"/org/freedesktop/portal/documents",
|
||||
)
|
||||
.await?;
|
||||
tokio::spawn(async move {
|
||||
let file_transfer = file_transfer_ref.get().await;
|
||||
let emitter = file_transfer_ref.signal_emitter();
|
||||
if let Err(err) = file_transfer.forward_transfer_closed(emitter.clone()).await {
|
||||
error!(%err, "forwarding forward_transfer_closed changes ended");
|
||||
}
|
||||
});
|
||||
|
||||
if !vm_bus_conn
|
||||
.object_server()
|
||||
.at("/org/freedesktop/portal/desktop", notification)
|
||||
.await?
|
||||
{
|
||||
error!("org.freedesktop.portal.Notification already provided");
|
||||
};
|
||||
let notification_ref = vm_bus_conn
|
||||
.object_server()
|
||||
.interface::<_, portal::notification::Notification>("/org/freedesktop/portal/desktop")
|
||||
.await?;
|
||||
tokio::spawn(async move {
|
||||
let notification = notification_ref.get().await;
|
||||
let emitter = notification_ref.signal_emitter();
|
||||
if let Err(err) = notification.forward_actions(emitter.clone()).await {
|
||||
error!(%err, "forwarding notification changes ended");
|
||||
}
|
||||
});
|
||||
|
||||
if !vm_bus_conn
|
||||
.object_server()
|
||||
.at("/org/freedesktop/portal/desktop", print)
|
||||
.await?
|
||||
{
|
||||
error!("org.freedesktop.portal.Print already provided");
|
||||
};
|
||||
|
||||
if !vm_bus_conn
|
||||
.object_server()
|
||||
.at("/org/freedesktop/portal/desktop", settings)
|
||||
|
|
@ -271,26 +181,21 @@ async fn main() -> eyre::Result<()> {
|
|||
error!(%err, "forwarding settings changes ended");
|
||||
}
|
||||
});
|
||||
|
||||
// XXX: no method for "wait until the conn dies"?
|
||||
Ok(std::future::pending::<()>().await)
|
||||
}
|
||||
|
||||
if let Some(path) = cli.unix_path {
|
||||
let vm_unix_listener = UnixListener::bind(path)?;
|
||||
server_tasks.spawn(enclose!((file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp) async move {
|
||||
server_tasks.spawn(enclose!((file_chooser_imp, settings_imp) async move {
|
||||
while let Ok((socket, remote_addr)) = vm_unix_listener.accept().await {
|
||||
let f = enclose!((file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp) async move {
|
||||
let client_conn = if cli.guest_bus_anonymous_auth {
|
||||
zbus::connection::Builder::unix_stream(socket).auth_mechanism(zbus::AuthMechanism::Anonymous)
|
||||
} else {
|
||||
zbus::connection::Builder::unix_stream(socket).user_id(cli.guest_uid)
|
||||
}
|
||||
let f = enclose!((file_chooser_imp, settings_imp) async move {
|
||||
let client_conn = zbus::connection::Builder::unix_stream(socket)
|
||||
.auth_mechanism(zbus::AuthMechanism::Anonymous)
|
||||
.name("org.freedesktop.portal.Desktop")?
|
||||
.name("org.freedesktop.portal.Documents")?
|
||||
.build()
|
||||
.await?;
|
||||
on_vm_bus_connected(client_conn, file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp).await
|
||||
on_vm_bus_connected(client_conn, file_chooser_imp, settings_imp).await
|
||||
});
|
||||
tokio::spawn(
|
||||
async {
|
||||
|
|
@ -311,10 +216,10 @@ async fn main() -> eyre::Result<()> {
|
|||
vsock::ListenerBuilder::new(vsock::VsockAddr::new(vsock::VMADDR_CID_HOST, port))
|
||||
.with_label("VM Bus")
|
||||
.listen(move |client| {
|
||||
enclose!((file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp) async move {
|
||||
enclose!((file_chooser_imp, settings_imp) async move {
|
||||
// TODO: Not necessary to go through the channel, add vsock support to the Peer too?
|
||||
let client_conn = client.build().await?;
|
||||
on_vm_bus_connected(client_conn, file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp).await
|
||||
on_vm_bus_connected(client_conn, file_chooser_imp, settings_imp).await
|
||||
})
|
||||
})
|
||||
.map_ok_or_else(
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ impl FileChooser {
|
|||
docs: self.docs.clone(),
|
||||
guest_root: self.guest_root.clone(),
|
||||
for_save: false,
|
||||
persistent: true,
|
||||
directory: options.get_as("directory")?.unwrap_or(false),
|
||||
})
|
||||
.perform(async || self.host.open_file(parent_window, title, options).await)
|
||||
|
|
@ -74,7 +73,6 @@ impl FileChooser {
|
|||
docs: self.docs.clone(),
|
||||
guest_root: self.guest_root.clone(),
|
||||
for_save: true,
|
||||
persistent: true,
|
||||
directory: false,
|
||||
})
|
||||
.perform(async || self.host.save_file(parent_window, title, options).await)
|
||||
|
|
@ -95,7 +93,6 @@ impl FileChooser {
|
|||
docs: self.docs.clone(),
|
||||
guest_root: self.guest_root.clone(),
|
||||
for_save: true,
|
||||
persistent: true,
|
||||
directory: false,
|
||||
})
|
||||
.perform(async || self.host.save_files(parent_window, title, options).await)
|
||||
|
|
@ -109,13 +106,11 @@ impl FileChooser {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FileTransformer {
|
||||
pub docs: DocumentsProxy<'static>,
|
||||
pub guest_root: PathBuf,
|
||||
pub for_save: bool,
|
||||
pub persistent: bool,
|
||||
pub directory: bool,
|
||||
struct FileTransformer {
|
||||
docs: DocumentsProxy<'static>,
|
||||
guest_root: PathBuf,
|
||||
for_save: bool,
|
||||
directory: bool,
|
||||
}
|
||||
|
||||
// ref: send_response_in_thread_func
|
||||
|
|
@ -139,14 +134,6 @@ impl ResultTransformer for FileTransformer {
|
|||
.async_map(|u| self.add_path_as_doc(u))
|
||||
.await
|
||||
.flatten()
|
||||
.map(|path| match url::Url::from_file_path(&path) {
|
||||
Ok(url) => Some(url.to_string()),
|
||||
Err(err) => {
|
||||
warn!(?err, ?path, "could not make url from returned path");
|
||||
None
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
results.insert("uris", guest_uris.into());
|
||||
|
|
@ -163,7 +150,7 @@ const DIRECTORY: u32 = 1 << 3;
|
|||
// https://github.com/flatpak/xdg-desktop-portal/blob/10e712e06aa8eb9cd0e59c73c5be62ba53e981a4/src/xdp-documents.c#L71
|
||||
|
||||
impl FileTransformer {
|
||||
pub async fn add_path_as_doc(&self, path: PathBuf) -> Option<PathBuf> {
|
||||
async fn add_path_as_doc(&self, path: PathBuf) -> Option<String> {
|
||||
use rustix::fs::{Mode, OFlags};
|
||||
|
||||
let o_path_fd = match rustix::fs::open(
|
||||
|
|
@ -179,8 +166,8 @@ impl FileTransformer {
|
|||
};
|
||||
|
||||
let flags = REUSE_EXISTING
|
||||
| PERSISTENT
|
||||
| AS_NEEDED_BY_APP
|
||||
| if self.persistent { PERSISTENT } else { 0 }
|
||||
| if self.directory { DIRECTORY } else { 0 };
|
||||
|
||||
// XXX: portal impl can return writable=false but host frontend does not pass that back..
|
||||
|
|
@ -225,7 +212,14 @@ impl FileTransformer {
|
|||
return None;
|
||||
}
|
||||
};
|
||||
Some(self.guest_root.join(doc_id).join(filename))
|
||||
let path = self.guest_root.join(doc_id).join(filename);
|
||||
match url::Url::from_file_path(&path) {
|
||||
Ok(url) => Some(url.to_string()),
|
||||
Err(err) => {
|
||||
warn!(?err, ?path, "could not make url from returned path");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,205 +0,0 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
os::fd::{AsFd, AsRawFd},
|
||||
os::unix::ffi::OsStrExt,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use tokio::sync::broadcast;
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::{debug, error};
|
||||
use zbus::{
|
||||
Connection, fdo::Result, names::OwnedUniqueName, object_server::SignalEmitter, zvariant,
|
||||
};
|
||||
|
||||
use super::{documents::DocumentsProxy, file_chooser::FileTransformer};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FileTransfer {
|
||||
host: FileTransferProxy<'static>,
|
||||
file_transformer: FileTransformer,
|
||||
tx: broadcast::Sender<ForwarderCommand>,
|
||||
path_prefix_to_host: Vec<(PathBuf, PathBuf)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum ForwarderCommand {
|
||||
Add(String, OwnedUniqueName),
|
||||
// Remove(String),
|
||||
}
|
||||
|
||||
#[zbus::interface(
|
||||
name = "org.freedesktop.portal.FileTransfer",
|
||||
proxy(
|
||||
default_service = "org.freedesktop.portal.Documents",
|
||||
default_path = "/org/freedesktop/portal/documents"
|
||||
)
|
||||
)]
|
||||
impl FileTransfer {
|
||||
async fn add_files(
|
||||
&self,
|
||||
key: &str,
|
||||
fds: Vec<zbus::zvariant::Fd<'_>>,
|
||||
options: HashMap<&str, zvariant::Value<'_>>,
|
||||
) -> Result<()> {
|
||||
let mut host_paths = Vec::with_capacity(fds.len());
|
||||
for fd in fds.iter() {
|
||||
let link = rustix::fs::readlink(
|
||||
format!("/proc/self/fd/{}", fd.as_fd().as_raw_fd()),
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(|e| zbus::fdo::Error::Failed(e.to_string()))?;
|
||||
let guest_path = std::path::PathBuf::from(std::ffi::OsStr::from_bytes(
|
||||
&link.to_string_lossy().as_bytes(),
|
||||
));
|
||||
let (prefix, host_prefix) = self
|
||||
.path_prefix_to_host
|
||||
.iter()
|
||||
.find(|(prefix, _)| guest_path.starts_with(prefix))
|
||||
.ok_or_else(|| {
|
||||
zbus::fdo::Error::Failed("Could not find host mapping for path".to_owned())
|
||||
})?;
|
||||
let guest_suffix = guest_path
|
||||
.strip_prefix(prefix)
|
||||
.map_err(|e| zbus::fdo::Error::Failed(e.to_string()))?;
|
||||
let host_path = if guest_suffix.as_os_str().is_empty() {
|
||||
// Edge case: a bind-mounted file exposed at the same path would get an extra '/' after its path
|
||||
host_prefix.to_path_buf()
|
||||
} else {
|
||||
host_prefix.join(guest_suffix)
|
||||
};
|
||||
debug!(
|
||||
?guest_path,
|
||||
?prefix,
|
||||
?guest_suffix,
|
||||
?host_prefix,
|
||||
?host_path,
|
||||
"mapped path"
|
||||
);
|
||||
let path_fd = rustix::fs::open(
|
||||
host_path,
|
||||
rustix::fs::OFlags::PATH,
|
||||
rustix::fs::Mode::empty(),
|
||||
)
|
||||
.map_err(|e| zbus::fdo::Error::Failed(e.to_string()))?;
|
||||
host_paths.push(path_fd.into()); // OwnedFd variant of zbus's Fd enum, so still owned by the Vec
|
||||
}
|
||||
self.host.add_files(key, host_paths, options).await
|
||||
}
|
||||
|
||||
async fn retrieve_files(
|
||||
&self,
|
||||
key: &str,
|
||||
options: HashMap<&str, zvariant::Value<'_>>,
|
||||
) -> Result<Vec<String>> {
|
||||
let host_paths = self.host.retrieve_files(key, options).await?;
|
||||
let mut result = Vec::with_capacity(host_paths.len());
|
||||
for host_path in host_paths {
|
||||
if let Some(guest_path) = self
|
||||
.file_transformer
|
||||
.add_path_as_doc(PathBuf::from(&host_path))
|
||||
.await
|
||||
{
|
||||
result.push(guest_path.to_string_lossy().into_owned());
|
||||
} else {
|
||||
debug!(%host_path, "could not add path as doc to retrieve file");
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn start_transfer(
|
||||
&self,
|
||||
#[zbus(header)] hdr: zbus::message::Header<'_>,
|
||||
options: HashMap<&str, zvariant::Value<'_>>,
|
||||
) -> Result<String> {
|
||||
let sender = hdr
|
||||
.sender()
|
||||
.ok_or_else(|| zbus::Error::MissingField)?
|
||||
.to_owned();
|
||||
let key = self.host.start_transfer(options).await?;
|
||||
debug!(%key, %sender, "started transfer");
|
||||
if let Err(err) = self
|
||||
.tx
|
||||
.send(ForwarderCommand::Add(key.clone(), sender.into()))
|
||||
{
|
||||
error!(?err, "file_transfer internal channel error");
|
||||
return Err(zbus::fdo::Error::IOError("channel error".to_owned()));
|
||||
}
|
||||
Ok(key)
|
||||
}
|
||||
|
||||
async fn stop_transfer(&self, key: &str) -> Result<()> {
|
||||
debug!(%key, "stopping transfer");
|
||||
self.host.stop_transfer(key).await
|
||||
}
|
||||
|
||||
#[zbus(signal)]
|
||||
async fn transfer_closed(signal_emitter: &SignalEmitter<'_>, key: &str) -> zbus::Result<()>;
|
||||
|
||||
#[zbus(property, name = "version")]
|
||||
fn version(&self) -> Result<u32> {
|
||||
Ok(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileTransfer {
|
||||
pub async fn new(
|
||||
host_session_conn: &Connection,
|
||||
priv_conn: &Connection,
|
||||
guest_root: PathBuf,
|
||||
path_prefix_to_host: Vec<(PathBuf, PathBuf)>,
|
||||
) -> Result<Self> {
|
||||
let host = FileTransferProxy::builder(host_session_conn)
|
||||
.build()
|
||||
.await?;
|
||||
let docs = DocumentsProxy::builder(priv_conn).build().await?;
|
||||
let file_transformer = FileTransformer {
|
||||
docs,
|
||||
guest_root,
|
||||
for_save: false,
|
||||
persistent: false,
|
||||
directory: false,
|
||||
};
|
||||
let (tx, _) = broadcast::channel(8);
|
||||
Ok(FileTransfer {
|
||||
host,
|
||||
file_transformer,
|
||||
tx,
|
||||
path_prefix_to_host,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn forward_transfer_closed(
|
||||
&self,
|
||||
mut signal_emitter: SignalEmitter<'static>,
|
||||
) -> Result<()> {
|
||||
let mut stream = self.host.receive_transfer_closed().await?;
|
||||
let mut cmds = self.tx.subscribe();
|
||||
let mut receivers = HashMap::new();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
Ok(cmd) = cmds.recv() => match cmd {
|
||||
ForwarderCommand::Add(key, receiver) => { receivers.insert(key, receiver); },
|
||||
// ForwarderCommand::Remove(key) => { receivers.remove(&key); },
|
||||
},
|
||||
Some(signal) = stream.next() => {
|
||||
debug!(?signal, "transfer closed");
|
||||
if let Ok((key,)) = signal.0.deserialize::<(&str,)>() {
|
||||
if let Some(bus_name) = receivers.remove(key) {
|
||||
signal_emitter = signal_emitter.set_destination(zbus::names::BusName::Unique(bus_name.clone().into()));
|
||||
if let Err(err) = FileTransfer::transfer_closed(&signal_emitter, key).await {
|
||||
error!(?err, %key, "could not forward signal");
|
||||
}
|
||||
} else {
|
||||
error!(%key, "got a signal for unknown key");
|
||||
}
|
||||
} else {
|
||||
error!("could not deserialize transfer closed signal");
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
pub mod documents;
|
||||
pub mod file_chooser;
|
||||
pub mod file_transfer;
|
||||
pub mod notification;
|
||||
pub mod print;
|
||||
pub mod request;
|
||||
pub mod settings;
|
||||
|
|
|
|||
|
|
@ -1,95 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::warn;
|
||||
use zbus::{Connection, fdo::Result, names::UniqueName, object_server::SignalEmitter, zvariant};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Notification {
|
||||
host: NotificationProxy<'static>,
|
||||
}
|
||||
|
||||
#[zbus::interface(
|
||||
name = "org.freedesktop.portal.Notification",
|
||||
proxy(
|
||||
default_service = "org.freedesktop.portal.Desktop",
|
||||
default_path = "/org/freedesktop/portal/desktop"
|
||||
)
|
||||
)]
|
||||
impl Notification {
|
||||
async fn add_notification(
|
||||
&self,
|
||||
#[zbus(header)] hdr: zbus::message::Header<'_>,
|
||||
id: &str,
|
||||
notification: HashMap<&str, zvariant::Value<'_>>,
|
||||
) -> Result<()> {
|
||||
let sender = hdr.sender().ok_or_else(|| zbus::Error::MissingField)?;
|
||||
self.host
|
||||
.add_notification(
|
||||
&format!("{sender}\x0C\x0CSIDEBUS\x0C\x0C{id}"),
|
||||
notification,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn remove_notification(
|
||||
&self,
|
||||
#[zbus(header)] hdr: zbus::message::Header<'_>,
|
||||
id: &str,
|
||||
) -> Result<()> {
|
||||
let sender = hdr.sender().ok_or_else(|| zbus::Error::MissingField)?;
|
||||
self.host
|
||||
.remove_notification(&format!("{sender}\x0C\x0CSIDEBUS\x0C\x0C{id}"))
|
||||
.await
|
||||
}
|
||||
|
||||
#[zbus(signal)]
|
||||
async fn action_invoked(
|
||||
signal_emitter: &SignalEmitter<'_>,
|
||||
id: &str,
|
||||
action: &str,
|
||||
parameter: Vec<zvariant::Value<'_>>,
|
||||
) -> zbus::Result<()>;
|
||||
|
||||
#[zbus(property)]
|
||||
async fn supported_options(&self) -> Result<HashMap<String, zvariant::OwnedValue>> {
|
||||
self.host
|
||||
.supported_options()
|
||||
.await
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
#[zbus(property, name = "version")]
|
||||
fn version(&self) -> Result<u32> {
|
||||
Ok(2)
|
||||
}
|
||||
}
|
||||
|
||||
impl Notification {
|
||||
pub async fn new(host_session_conn: &Connection) -> Result<Self> {
|
||||
let host = NotificationProxy::builder(host_session_conn)
|
||||
.build()
|
||||
.await?;
|
||||
Ok(Self { host })
|
||||
}
|
||||
|
||||
pub async fn forward_actions(&self, mut signal_emitter: SignalEmitter<'static>) -> Result<()> {
|
||||
let mut stream = self.host.receive_action_invoked().await?;
|
||||
while let Some(x) = stream.next().await {
|
||||
let args = x.args()?;
|
||||
let mut split = args.id.split("\x0C\x0CSIDEBUS\x0C\x0C");
|
||||
let sender = split
|
||||
.next()
|
||||
.and_then(|x| UniqueName::try_from(x).ok().map(|x| x.to_owned()))
|
||||
.ok_or_else(|| zbus::fdo::Error::Failed("bad ID".to_owned()))?;
|
||||
let id = split
|
||||
.next()
|
||||
.ok_or_else(|| zbus::fdo::Error::Failed("bad ID".to_owned()))?;
|
||||
signal_emitter = signal_emitter.set_destination(sender.into());
|
||||
Notification::action_invoked(&signal_emitter, id, args.action, args.parameter).await?;
|
||||
()
|
||||
}
|
||||
warn!("actions stream end");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use zbus::{Connection, ObjectServer, fdo::Result, zvariant};
|
||||
|
||||
use super::request::ReqHandler;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Print {
|
||||
host: PrintProxy<'static>,
|
||||
}
|
||||
|
||||
#[zbus::interface(
|
||||
name = "org.freedesktop.portal.Print",
|
||||
proxy(
|
||||
default_service = "org.freedesktop.portal.Desktop",
|
||||
default_path = "/org/freedesktop/portal/desktop"
|
||||
)
|
||||
)]
|
||||
impl Print {
|
||||
async fn prepare_print(
|
||||
&self,
|
||||
#[zbus(header)] hdr: zbus::message::Header<'_>,
|
||||
#[zbus(object_server)] server: &ObjectServer,
|
||||
#[zbus(connection)] conn: &Connection,
|
||||
parent_window: &str,
|
||||
title: &str,
|
||||
settings: HashMap<&str, zvariant::Value<'_>>,
|
||||
page_setup: HashMap<&str, zvariant::Value<'_>>,
|
||||
options: HashMap<&str, zvariant::Value<'_>>,
|
||||
) -> Result<zvariant::OwnedObjectPath> {
|
||||
ReqHandler::prepare(&self.host, hdr, server, conn, &options)
|
||||
.perform(async || {
|
||||
self.host
|
||||
.prepare_print(parent_window, title, settings, page_setup, options)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn print(
|
||||
&self,
|
||||
#[zbus(header)] hdr: zbus::message::Header<'_>,
|
||||
#[zbus(object_server)] server: &ObjectServer,
|
||||
#[zbus(connection)] conn: &Connection,
|
||||
parent_window: &str,
|
||||
title: &str,
|
||||
fd: zvariant::Fd<'_>,
|
||||
options: HashMap<&str, zvariant::Value<'_>>,
|
||||
) -> Result<zvariant::OwnedObjectPath> {
|
||||
ReqHandler::prepare(&self.host, hdr, server, conn, &options)
|
||||
.perform(async || self.host.print(parent_window, title, fd, options).await)
|
||||
.await
|
||||
}
|
||||
|
||||
#[zbus(property, name = "version")]
|
||||
fn version(&self) -> Result<u32> {
|
||||
Ok(3)
|
||||
}
|
||||
}
|
||||
|
||||
impl Print {
|
||||
pub async fn new(host_session_conn: &Connection) -> Result<Self> {
|
||||
let host = PrintProxy::builder(host_session_conn).build().await?;
|
||||
Ok(Self { host })
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@ impl ConnectionBuilder {
|
|||
zbus::connection::Builder::vsock_stream(self.socket)
|
||||
.auth_mechanism(zbus::AuthMechanism::Anonymous)
|
||||
.name("org.freedesktop.portal.Desktop")?
|
||||
.name("org.freedesktop.portal.Documents")?
|
||||
.build()
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue