feat: enable autostart during the service setup (#1146)

This commit is contained in:
Ilya Zlobintsev
2026-08-10 14:16:12 +03:00
committed by GitHub
parent f4da14868b
commit e748e9f905
4 changed files with 68 additions and 11 deletions
+2
View File
@@ -254,6 +254,8 @@ service-logs = Service Logs
service-start = Start
service-stop = Stop
service-restart = Restart
service-autostart = Autostart on boot
service-autostart-disable = Also disable autostart
version-mismatch-description =
Version mismatch between GUI and Daemon ({$gui_version}-{$gui_commit} vs {$daemon_version}-{$daemon_commit})!
+6 -2
View File
@@ -666,10 +666,13 @@ impl AppModel {
self.overdrive_dialog.emit(OverdriveDialogMsg::Show);
}
AppMsg::ShowServiceSetupDialog => {
let (manager_proxy, unit_proxy) = systemd::connect_unit_proxy().await?;
let params = ServiceSetupDialogParams {
parent: root.clone().upcast(),
initial_client: Ok((self.daemon_client.clone(), self.system_info.clone())),
unit_proxy: systemd::connect_unit_proxy().await?,
manager_proxy,
unit_proxy,
};
let controller = ServiceSetupDialog::builder()
.launch(params)
@@ -1431,10 +1434,11 @@ async fn create_connection(
Ok(client) => (client, false),
Err(err) => {
let configured_client = match connect_unit_proxy().await {
Ok(unit_proxy) => {
Ok((manager_proxy, unit_proxy)) => {
let params = ServiceSetupDialogParams {
parent: root.clone().upcast(),
initial_client: Err(err),
manager_proxy,
unit_proxy,
};
let service_setup = ServiceSetupDialog::builder().launch(params).into_stream();
+48 -4
View File
@@ -3,12 +3,13 @@ pub mod systemd;
use crate::I18N;
use crate::app::components::info_row::{InfoRow, InfoRowExt};
use crate::app::utils::ext::FlowBoxExt;
use crate::service_setup::systemd::{START_MODE_REPLACE, UnitProxy};
use crate::service_setup::systemd::{ManagerProxy, START_MODE_REPLACE, UNIT_NAME, UnitProxy};
use adw::prelude::*;
use anyhow::{Context as _, anyhow};
use i18n_embed_fl::fl;
use lact_client::DaemonClient;
use lact_schema::{SystemInfo, VersionInfo};
use relm4::binding::{BoolBinding, ConnectBinding as _};
use relm4::{
AsyncComponentSender, RelmWidgetExt,
css::{self, ERROR, SUCCESS, WARNING},
@@ -22,15 +23,19 @@ use tracing::debug;
pub struct ServiceSetupDialog {
connection_status: ConnectionStatus,
manager_proxy: ManagerProxy<'static>,
unit_proxy: UnitProxy<'static>,
service_logs: gtk::TextBuffer,
service_state: String,
autostart_on_start: BoolBinding,
autostart_on_stop: BoolBinding,
setup_error: Option<anyhow::Error>,
}
pub struct ServiceSetupDialogParams {
pub parent: gtk::ApplicationWindow,
pub initial_client: anyhow::Result<(DaemonClient, SystemInfo)>,
pub manager_proxy: ManagerProxy<'static>,
pub unit_proxy: UnitProxy<'static>,
}
@@ -188,17 +193,35 @@ impl AsyncComponent for ServiceSetupDialog {
set_hexpand: true,
set_halign: gtk::Align::End,
gtk::Button {
adw::SplitButton {
set_label: &fl!(I18N, "service-start"),
connect_clicked => ServiceSetupDialogMsg::StartService,
add_css_class: "suggested-action",
#[wrap(Some)]
set_popover = &gtk::Popover {
gtk::CheckButton {
set_label: Some(&fl!(I18N, "service-autostart")),
bind: &model.autostart_on_start,
},
},
#[watch]
set_visible: model.service_state != systemd::UNIT_STATE_ACTIVE,
},
gtk::Button {
adw::SplitButton {
set_label: &fl!(I18N, "service-stop"),
connect_clicked => ServiceSetupDialogMsg::StopService,
#[wrap(Some)]
set_popover = &gtk::Popover {
gtk::CheckButton {
set_label: Some(&fl!(I18N, "service-autostart-disable")),
bind: &model.autostart_on_stop,
},
},
#[watch]
set_visible: model.service_state == systemd::UNIT_STATE_ACTIVE,
},
@@ -253,7 +276,10 @@ impl AsyncComponent for ServiceSetupDialog {
let model = Self {
connection_status,
manager_proxy: params.manager_proxy,
unit_proxy: params.unit_proxy,
autostart_on_start: BoolBinding::new(true),
autostart_on_stop: BoolBinding::new(true),
service_logs: gtk::TextBuffer::builder()
.text(service_logs_handle.await.unwrap())
.build(),
@@ -289,12 +315,30 @@ impl ServiceSetupDialog {
match msg {
ServiceSetupDialogMsg::Reconnect => (),
ServiceSetupDialogMsg::StartService => {
self.unit_proxy.start(START_MODE_REPLACE).await?;
// Note: this order is important, doing it the other way around causes 2 polkit prompts
if self.autostart_on_start.value() {
self.manager_proxy
.enable_unit_files(&[UNIT_NAME], false, true)
.await
.context("could not enable unit")?;
}
self.unit_proxy
.start(START_MODE_REPLACE)
.await
.context("could not start unit")?;
}
ServiceSetupDialogMsg::RestartService => {
self.unit_proxy.restart(START_MODE_REPLACE).await?;
}
ServiceSetupDialogMsg::StopService => {
if self.autostart_on_stop.value() {
self.manager_proxy
.disable_unit_files(&[UNIT_NAME], false)
.await
.context("could not disable unit")?;
}
self.unit_proxy.stop(START_MODE_REPLACE).await?;
}
ServiceSetupDialogMsg::Close => {
+12 -5
View File
@@ -3,13 +3,13 @@ use anyhow::{Context, bail};
use relm4::tokio::process::Command;
use zbus::{proxy, zvariant::OwnedObjectPath};
const UNIT_NAME: &str = "lactd.service";
pub const UNIT_NAME: &str = "lactd.service";
pub const UNIT_STATE_ACTIVE: &str = "active";
pub const START_MODE_REPLACE: &str = "replace";
pub async fn connect_unit_proxy() -> anyhow::Result<UnitProxy<'static>> {
pub async fn connect_unit_proxy() -> anyhow::Result<(ManagerProxy<'static>, UnitProxy<'static>)> {
let conn = zbus::Connection::system()
.await
.context("Could not establish DBus connection")?;
@@ -19,7 +19,7 @@ pub async fn connect_unit_proxy() -> anyhow::Result<UnitProxy<'static>> {
.context("Could not connect to systemd manager interface")?;
let path = manager
.get_unit(UNIT_NAME)
.load_unit(UNIT_NAME)
.await
.context("Could not get lact systemd unit")?;
@@ -29,7 +29,7 @@ pub async fn connect_unit_proxy() -> anyhow::Result<UnitProxy<'static>> {
.await
.context("Could not connect to systemd unit interface")?;
Ok(unit)
Ok((manager, unit))
}
#[proxy(
@@ -39,7 +39,7 @@ pub async fn connect_unit_proxy() -> anyhow::Result<UnitProxy<'static>> {
)]
pub trait Manager {
#[zbus(allow_interactive_auth)]
fn get_unit(&self, name: &str) -> zbus::Result<OwnedObjectPath>;
fn load_unit(&self, name: &str) -> zbus::Result<OwnedObjectPath>;
#[zbus(allow_interactive_auth)]
fn enable_unit_files(
@@ -48,6 +48,13 @@ pub trait Manager {
runtime: bool,
force: bool,
) -> zbus::Result<(bool, Vec<(String, String, String)>)>;
#[zbus(allow_interactive_auth)]
fn disable_unit_files(
&self,
files: &[&str],
runtime: bool,
) -> zbus::Result<Vec<(String, String, String)>>;
}
#[proxy(