Skip to content
Open
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
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ ashpd = { version = "0.12", default-features = false, features = [
futures-timer = "3.0.3"
tokio-util = "0.7.15"
tracing-appender = "0.2.3"
const-str = "0.7.0"
3 changes: 3 additions & 0 deletions data/io.github.nozwock.Packet.Api.service.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[D-BUS Service]
Name=@app-id@
Exec=@bindir@/packet --background
11 changes: 11 additions & 0 deletions data/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,14 @@ configure_file(
install: true,
install_dir: datadir / 'dbus-1' / 'services'
)

service_conf = configuration_data()
service_conf.set('app-id', api_id)
service_conf.set('bindir', bindir)
configure_file(
input: '@0@.service.in'.format(base_id + '.Api'),
output: '@0@.service'.format(api_id),
configuration: service_conf,
install: true,
install_dir: datadir / 'dbus-1' / 'services'
)
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ else
application_id = base_id
endif

api_id = application_id + '.Api'

meson.add_dist_script(
'build-aux/dist-vendor.sh',
meson.project_build_root() / 'meson-dist' / meson.project_name()
Expand All @@ -70,4 +72,4 @@ gnome.post_install(
gtk_update_icon_cache: true,
glib_compile_schemas: true,
update_desktop_database: true,
)
)
3 changes: 3 additions & 0 deletions src/config.rs.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ pub const PKGDATADIR: &str = @PKGDATADIR@;
pub const PROFILE: &str = @PROFILE@;
pub const RESOURCES_FILE: &str = concat!(@PKGDATADIR@, "/resources.gresource");
pub const VERSION: &str = @VERSION@;

pub const DBUS_API_NAME: &str = const_str::concat!(APP_ID, ".Api");
pub const DBUS_API_PATH: &str = const_str::concat!("/", const_str::replace!(APP_ID, ".", "/"));
90 changes: 90 additions & 0 deletions src/dbus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use std::sync::{Arc, LazyLock};

use tokio::sync::{
Mutex,
mpsc::{Receiver, Sender, channel},
};
use zbus::{Connection, object_server::InterfaceRef};

use crate::config::{DBUS_API_NAME, DBUS_API_PATH};

#[derive(Debug)]
pub struct Packet {
pub device_name: String,
pub visibility: bool,
visibility_tx: Arc<Mutex<Sender<bool>>>,
pub visibility_rx: Arc<Mutex<Receiver<bool>>>,
}

#[zbus::interface(name = "io.github.nozwock.Packet1")]
impl Packet {
#[zbus(property)]
pub async fn device_name(&self) -> &str {
&self.device_name
}

#[zbus(property)]
pub async fn device_visibility(&self) -> bool {
self.visibility
}

/// Also sends the param to the channel associated with `visibility_tx`.
#[zbus(property)]
pub async fn set_device_visibility(&mut self, visibility: bool) {
self.visibility = visibility;
_ = self
.visibility_tx
.lock()
.await
.send(visibility)
.await
.inspect_err(|err| tracing::warn!(%err));
}
}

static CONNECTION: LazyLock<Mutex<Option<Connection>>> = LazyLock::new(|| Mutex::new(None));

pub async fn get_connection() -> Option<Connection> {
CONNECTION.lock().await.as_ref().cloned()
}

pub async fn create_connection(
device_name: String,
visibility: bool,
) -> anyhow::Result<Connection> {
let mut conn_guard = CONNECTION.lock().await;

if let Some(conn) = conn_guard.as_ref() {
Ok(conn.clone())
} else {
let (tx, rx) = channel::<bool>(1);
let conn = zbus::connection::Builder::session()?
.name(DBUS_API_NAME)?
.serve_at(
DBUS_API_PATH,
Packet {
device_name,
visibility,
visibility_tx: Arc::new(Mutex::new(tx)),
visibility_rx: Arc::new(Mutex::new(rx)),
},
)?
.build()
.await?;
*conn_guard = Some(conn.clone());

Ok(conn)
}
}

/// # Panics
/// Panics if `CONNECTION` is `None`.
pub async fn packet_iface() -> InterfaceRef<Packet> {
get_connection()
.await
.expect("Session should be created before getting iface")
.object_server()
.interface::<_, Packet>(DBUS_API_PATH)
.await
.expect("Interface should be on the object path")
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod application;
#[rustfmt::skip]
mod config;
mod constants;
mod dbus;
mod ext;
mod monitors;
mod objects;
Expand Down
140 changes: 122 additions & 18 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use tokio_util::sync::CancellationToken;
use crate::application::PacketApplication;
use crate::config::{APP_ID, PROFILE};
use crate::constants::packet_log_path;
use crate::dbus;
use crate::ext::MessageExt;
use crate::objects::{self, SendRequestState};
use crate::objects::{TransferState, UserAction};
Expand Down Expand Up @@ -171,6 +172,7 @@ mod imp {
pub is_mdns_discovery_on: Rc<Cell<bool>>,

pub looping_async_tasks: RefCell<Vec<LoopingTaskHandle>>,
pub dbus_async_tasks: RefCell<Vec<LoopingTaskHandle>>,

pub is_background_allowed: Cell<bool>,
pub should_quit: Cell<bool>,
Expand Down Expand Up @@ -216,6 +218,7 @@ mod imp {
obj.setup_notification_actions_monitor();
obj.setup_rqs_service();
obj.request_background_at_start();
obj.setup_dbus_api();
}
}

Expand Down Expand Up @@ -265,9 +268,16 @@ mod imp {

// Abort all looping tasks before closing
tracing::info!(
count = self.looping_async_tasks.borrow().len(),
rqs_tasks = self.looping_async_tasks.borrow().len(),
dbus_tasks = self.dbus_async_tasks.borrow().len(),
"Cancelling looping tasks"
);
while let Some(join_handle) = self.dbus_async_tasks.borrow_mut().pop() {
match join_handle {
LoopingTaskHandle::Tokio(join_handle) => join_handle.abort(),
LoopingTaskHandle::Glib(join_handle) => join_handle.abort(),
}
}
while let Some(join_handle) = self.looping_async_tasks.borrow_mut().pop() {
match join_handle {
LoopingTaskHandle::Tokio(join_handle) => join_handle.abort(),
Expand Down Expand Up @@ -1495,6 +1505,24 @@ impl PacketApplicationWindow {
));
}

async fn on_visibility_changed(&self, visibility: bool) {
let imp = self.imp();

self.bottom_bar_status_indicator_ui_update(visibility);

if let Some(rqs) = imp.rqs.lock().await.as_mut() {
let visibility = if visibility {
rqs_lib::Visibility::Visible
} else {
rqs_lib::Visibility::Invisible
};

rqs.change_visibility(visibility);
} else {
tracing::warn!("Couldn't set device visibility due RQS not being set");
}
}

fn bottom_bar_status_indicator_ui_update(&self, is_visible: bool) {
let imp = self.imp();

Expand Down Expand Up @@ -1578,23 +1606,15 @@ impl PacketApplicationWindow {
#[weak]
imp,
move |obj| {
imp.obj()
.bottom_bar_status_indicator_ui_update(obj.is_active());

let visibility = if obj.is_active() {
rqs_lib::Visibility::Visible
} else {
rqs_lib::Visibility::Invisible
};

glib::spawn_future_local(async move {
imp.rqs
.lock()
.await
.as_mut()
.unwrap()
.change_visibility(visibility);
});
glib::spawn_future_local(clone!(
#[weak]
imp,
#[weak]
obj,
async move {
imp.obj().on_visibility_changed(obj.is_active()).await;
}
));
}
));
}
Expand Down Expand Up @@ -1849,6 +1869,90 @@ impl PacketApplicationWindow {
handle
}

fn setup_dbus_api(&self) {
let obj = self.clone();

let inner = async move || -> anyhow::Result<()> {
let imp = obj.imp();

_ = dbus::create_connection(
obj.get_device_name_state().as_str().to_string(),
imp.settings.boolean("device-visibility"),
)
.await?;

let handle = glib::spawn_future_local(clone!(
#[weak]
imp,
async move {
// IMPORTANT: Keep notice of get() and get_mut() so that it doesn't lead to deadlock
let mut visibility_rx = {
let iface_ref = dbus::packet_iface().await;
iface_ref
.get()
.await
.visibility_rx
.clone()
.lock_owned()
.await
};

while let Some(extern_visibility) = visibility_rx.recv().await {
_ = imp
.settings
.set_boolean("device-visibility", extern_visibility)
.inspect_err(|err| tracing::warn!(%err));
}
}
));
imp.dbus_async_tasks
.borrow_mut()
.push(LoopingTaskHandle::Glib(handle));

imp.settings
.connect_changed(None, move |settings, key| match key {
"device-visibility" | "device-name" => {
let key = key.to_string();
glib::spawn_future_local(clone!(
#[weak]
settings,
async move {
let iface_ref = dbus::packet_iface().await;
let mut iface = iface_ref.get_mut().await;
match key.as_str() {
"device-name" => {
iface.device_name =
settings.string(&key).as_str().to_string();
_ = iface
.device_name_changed(iface_ref.signal_emitter())
.await
.inspect_err(|err| tracing::warn!(%err));
}
"device-visibility" => {
iface.visibility = settings.boolean(&key);
_ = iface
.device_visibility_changed(iface_ref.signal_emitter())
.await
.inspect_err(|err| tracing::warn!(%err));
}
_ => {}
}
}
));
}
_ => {}
});

Ok(())
};

glib::spawn_future_local(async move {
_ = inner()
.await
.inspect_err(|err| tracing::error!(%err, "Failed to setup DBus API"));
});
}

fn setup_connection_monitors(&self) {
let imp = self.imp();

Expand Down
Loading