Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/gio_dbus_register_object/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ enum HelloMethod {
impl DBusMethodCall for HelloMethod {
fn parse_call(
_obj_path: &str,
_interface: &str,
_interface: Option<&str>,
method: &str,
params: glib::Variant,
) -> Result<Self, glib::Error> {
Expand All @@ -65,7 +65,7 @@ fn on_startup(app: &gio::Application, tx: &Sender<gio::RegistrationId>) {
.register_object("/com/github/gtk_rs/examples/HelloWorld", &example)
.typed_method_call::<HelloMethod>()
.invoke_and_return_future_local(|_, sender, call| {
println!("Method call from {sender}");
println!("Method call from {sender:?}");
async {
match call {
HelloMethod::Hello(Hello { name }) => {
Expand Down
11 changes: 10 additions & 1 deletion gio/Gir.toml
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,16 @@ status = "generate"
name = "return_error_literal"
# glib::ErrorDomain
manual = true

[[object.function]]
name = "get_sender"
[object.function.return]
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4414
nullable = true
[[object.function]]
name = "get_interface_name"
[object.function.return]
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4414
nullable = true

[[object]]
name = "Gio.DBusProxy"
Expand Down
4 changes: 2 additions & 2 deletions gio/src/auto/dbus_method_invocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl DBusMethodInvocation {

#[doc(alias = "g_dbus_method_invocation_get_interface_name")]
#[doc(alias = "get_interface_name")]
pub fn interface_name(&self) -> glib::GString {
pub fn interface_name(&self) -> Option<glib::GString> {
unsafe {
from_glib_none(ffi::g_dbus_method_invocation_get_interface_name(
self.to_glib_none().0,
Expand Down Expand Up @@ -103,7 +103,7 @@ impl DBusMethodInvocation {

#[doc(alias = "g_dbus_method_invocation_get_sender")]
#[doc(alias = "get_sender")]
pub fn sender(&self) -> glib::GString {
pub fn sender(&self) -> Option<glib::GString> {
unsafe {
from_glib_none(ffi::g_dbus_method_invocation_get_sender(
self.to_glib_none().0,
Expand Down
50 changes: 36 additions & 14 deletions gio/src/dbus_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use glib::{prelude::*, translate::*};
pub trait DBusMethodCall: Sized {
fn parse_call(
obj_path: &str,
interface: &str,
interface: Option<&str>,
method: &str,
params: glib::Variant,
) -> Result<Self, glib::Error>;
Expand Down Expand Up @@ -46,7 +46,7 @@ impl<'a, T: DBusMethodCall> MethodCallBuilder<'a, T> {
/// safer interface where the callback returns a result directly.
pub fn invoke<F>(self, f: F) -> RegistrationBuilder<'a>
where
F: Fn(DBusConnection, &str, T, DBusMethodInvocation) + 'static,
F: Fn(DBusConnection, Option<&str>, T, DBusMethodInvocation) + 'static,
{
self.registration.method_call(
move |connection, sender, obj_path, interface, method, params, invocation| {
Expand Down Expand Up @@ -74,7 +74,8 @@ impl<'a, T: DBusMethodCall> MethodCallBuilder<'a, T> {
/// See [`DBusMethodInvocation::return_result`] for details.
pub fn invoke_and_return<F>(self, f: F) -> RegistrationBuilder<'a>
where
F: Fn(DBusConnection, &str, T) -> Result<Option<glib::Variant>, glib::Error> + 'static,
F: Fn(DBusConnection, Option<&str>, T) -> Result<Option<glib::Variant>, glib::Error>
+ 'static,
{
self.invoke(move |connection, sender, call, invocation| {
invocation.return_result(f(connection, sender, call))
Expand All @@ -97,7 +98,7 @@ impl<'a, T: DBusMethodCall> MethodCallBuilder<'a, T> {
/// See [`DBusMethodInvocation::return_future_local`] for details.
pub fn invoke_and_return_future_local<F, Fut>(self, f: F) -> RegistrationBuilder<'a>
where
F: Fn(DBusConnection, &str, T) -> Fut + 'static,
F: Fn(DBusConnection, Option<&str>, T) -> Fut + 'static,
Fut: Future<Output = Result<Option<glib::Variant>, glib::Error>> + 'static,
{
self.invoke(move |connection, sender, call, invocation| {
Expand Down Expand Up @@ -128,18 +129,37 @@ pub struct RegistrationBuilder<'a> {
interface_info: &'a DBusInterfaceInfo,
#[allow(clippy::type_complexity)]
method_call: Option<
Box_<dyn Fn(DBusConnection, &str, &str, &str, &str, glib::Variant, DBusMethodInvocation)>,
Box_<
dyn Fn(
DBusConnection,
Option<&str>,
&str,
Option<&str>,
&str,
glib::Variant,
DBusMethodInvocation,
),
>,
>,
#[allow(clippy::type_complexity)]
get_property: Option<Box_<dyn Fn(DBusConnection, &str, &str, &str, &str) -> glib::Variant>>,
get_property:
Option<Box_<dyn Fn(DBusConnection, Option<&str>, &str, &str, &str) -> glib::Variant>>,
#[allow(clippy::type_complexity)]
set_property:
Option<Box_<dyn Fn(DBusConnection, &str, &str, &str, &str, glib::Variant) -> bool>>,
Option<Box_<dyn Fn(DBusConnection, Option<&str>, &str, &str, &str, glib::Variant) -> bool>>,
}

impl<'a> RegistrationBuilder<'a> {
pub fn method_call<
F: Fn(DBusConnection, &str, &str, &str, &str, glib::Variant, DBusMethodInvocation) + 'static,
F: Fn(
DBusConnection,
Option<&str>,
&str,
Option<&str>,
&str,
glib::Variant,
DBusMethodInvocation,
) + 'static,
>(
mut self,
f: F,
Expand All @@ -162,7 +182,9 @@ impl<'a> RegistrationBuilder<'a> {
}

#[doc(alias = "get_property")]
pub fn property<F: Fn(DBusConnection, &str, &str, &str, &str) -> glib::Variant + 'static>(
pub fn property<
F: Fn(DBusConnection, Option<&str>, &str, &str, &str) -> glib::Variant + 'static,
>(
mut self,
f: F,
) -> Self {
Expand All @@ -171,7 +193,7 @@ impl<'a> RegistrationBuilder<'a> {
}

pub fn set_property<
F: Fn(DBusConnection, &str, &str, &str, &str, glib::Variant) -> bool + 'static,
F: Fn(DBusConnection, Option<&str>, &str, &str, &str, glib::Variant) -> bool + 'static,
>(
mut self,
f: F,
Expand All @@ -191,9 +213,9 @@ impl<'a> RegistrationBuilder<'a> {
.map(|f| {
glib::Closure::new_local(move |args| {
let conn = args[0].get::<DBusConnection>().unwrap();
let sender = args[1].get::<&str>().unwrap();
let sender = args[1].get::<Option<&str>>().unwrap();
let object_path = args[2].get::<&str>().unwrap();
let interface_name = args[3].get::<&str>().unwrap();
let interface_name = args[3].get::<Option<&str>>().unwrap();
let method_name = args[4].get::<&str>().unwrap();
let parameters = args[5].get::<glib::Variant>().unwrap();
let invocation = args[6].get::<DBusMethodInvocation>().unwrap();
Expand All @@ -215,7 +237,7 @@ impl<'a> RegistrationBuilder<'a> {
.map(|f| {
glib::Closure::new_local(move |args| {
let conn = args[0].get::<DBusConnection>().unwrap();
let sender = args[1].get::<&str>().unwrap();
let sender = args[1].get::<Option<&str>>().unwrap();
let object_path = args[2].get::<&str>().unwrap();
let interface_name = args[3].get::<&str>().unwrap();
let property_name = args[4].get::<&str>().unwrap();
Expand All @@ -237,7 +259,7 @@ impl<'a> RegistrationBuilder<'a> {
.map(|f| {
glib::Closure::new_local(move |args| {
let conn = args[0].get::<DBusConnection>().unwrap();
let sender = args[1].get::<&str>().unwrap();
let sender = args[1].get::<Option<&str>>().unwrap();
let object_path = args[2].get::<&str>().unwrap();
let interface_name = args[3].get::<&str>().unwrap();
let property_name = args[4].get::<&str>().unwrap();
Expand Down
157 changes: 157 additions & 0 deletions gio/tests/dbus_peer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Take a look at the license at the top of the repository in the LICENSE file.

#[cfg(unix)]
#[test]
fn test_gdbus_peer_connection() {
use gio::{
glib::{self, VariantTy},
prelude::*,
DBusConnection, DBusConnectionFlags, DBusNodeInfo, Socket,
};
use std::os::{fd::IntoRawFd, unix::net::UnixStream};

const EXAMPLE_XML: &str = r#"
<node>
<interface name='com.github.gtk_rs'>
<method name='Hello'>
<arg type='s' name='name' direction='in'/>
<arg type='s' name='greet' direction='out'/>
</method>
</interface>
</node>
"#;

pub async fn spawn_server(fd: UnixStream) -> DBusConnection {
let socket = unsafe { Socket::from_fd(fd.into_raw_fd()) }.unwrap();
let socket_connection = socket.connection_factory_create_connection();

let guid = gio::dbus_generate_guid();

dbg!("server connecting");

let connection = DBusConnection::new_future(
&socket_connection,
Some(&guid),
DBusConnectionFlags::AUTHENTICATION_SERVER
.union(DBusConnectionFlags::DELAY_MESSAGE_PROCESSING),
None,
)
.await
.unwrap();

dbg!("server connected");

let interface_info = DBusNodeInfo::for_xml(EXAMPLE_XML)
.unwrap()
.lookup_interface("com.github.gtk_rs")
.unwrap();

let _id = connection
.register_object("/com/github/gtk_rs", &interface_info)
.method_call(
|_connection,
_sender,
_object_path,
_interface_name,
_method_name,
parameters,
invocation| {
dbg!(
_sender,
_object_path,
_interface_name,
_method_name,
&parameters,
&invocation
);

let name = parameters.child_get::<String>(0);
invocation.return_value(Some(&(format!("Hello {name}!"),).to_variant()));
},
)
.build()
.unwrap();

dbg!("server starts message processing");

connection.start_message_processing();

dbg!("server awaiting calls");

connection
}

pub async fn spawn_client(fd: UnixStream) -> DBusConnection {
let socket_client = unsafe { Socket::from_fd(fd.into_raw_fd()) }.unwrap();
let socket_connection_client = socket_client.connection_factory_create_connection();

dbg!("client connecting");

let connection = DBusConnection::new_future(
&socket_connection_client,
None,
DBusConnectionFlags::AUTHENTICATION_CLIENT,
None,
)
.await
.unwrap();

dbg!("client connected");

connection
}

let ctx = glib::MainContext::default();

let (x, y) = std::os::unix::net::UnixStream::pair().unwrap();

x.set_nonblocking(true).unwrap();
y.set_nonblocking(true).unwrap();

ctx.block_on(async move {
let ctx = glib::MainContext::default();

let server = ctx.spawn_local(spawn_server(x));
let client = ctx.spawn_local(spawn_client(y));

let server = server.await.unwrap();
let client = client.await.unwrap();

dbg!("calling method");

let result = client
.call_future(
None,
"/com/github/gtk_rs",
"com.github.gtk_rs",
"Hello",
Some(&("World",).into()),
Some(VariantTy::new("(s)").unwrap()),
gio::DBusCallFlags::NONE,
10000,
)
.await
.unwrap();

dbg!("method called");

dbg!(&result);

dbg!("closing client");
client.close_future().await.unwrap();
dbg!("closed client, closing server");
server.close_future().await.unwrap();
dbg!("closed server");

drop(client);
drop(server);

assert_eq!(result.child_get::<String>(0), "Hello World!");

glib::timeout_future_with_priority(
glib::Priority::LOW,
std::time::Duration::from_millis(50),
)
.await;
});
}
Loading