Skip to content

Commit 32affcc

Browse files
authored
Merge pull request #38 from matheus-git/develop
Visual feedback, mask/unmask and wait until start/stop/restart completes
2 parents faf5a7d + 4c8ad73 commit 32affcc

File tree

5 files changed

+114
-19
lines changed

5 files changed

+114
-19
lines changed

src/domain/service_repository.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub trait ServiceRepository {
1313
fn restart_service(&self, name: &str) -> Result<Service, Box<dyn Error>>;
1414
fn enable_service(&self, name: &str) -> Result<Service, Box<dyn Error>>;
1515
fn disable_service(&self, name: &str) -> Result<Service, Box<dyn Error>>;
16+
fn mask_service(&self, name: &str) -> Result<Service, Box<dyn Error>>;
17+
fn unmask_service(&self, name: &str) -> Result<Service, Box<dyn Error>>;
1618
fn reload_daemon(&self) -> Result<(), Box<dyn std::error::Error>>;
1719
fn change_connection(&mut self, connection_type: ConnectionType) -> Result<(), zbus::Error>;
1820
fn systemctl_cat(&self, name: &str) -> Result<String, Box<dyn Error>>;

src/infrastructure/systemd_service_adapter.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,21 +191,36 @@ impl ServiceRepository for SystemdServiceAdapter {
191191
let proxy = self.manager_proxy()?;
192192
let _job: OwnedObjectPath = proxy.call("StartUnit", &(name, "replace"))?;
193193
thread::sleep(Duration::from_millis(SLEEP_DURATION));
194-
self.get_unit(name)
194+
let mut service = self.get_unit(name)?;
195+
while service.state().active().ends_with("ing") {
196+
service = self.get_unit(name)?;
197+
thread::sleep(Duration::from_millis(100));
198+
}
199+
Ok(service)
195200
}
196201

197202
fn stop_service(&self, name: &str) -> Result<Service, Box<dyn std::error::Error>> {
198203
let proxy = self.manager_proxy()?;
199204
let _job: OwnedObjectPath = proxy.call("StopUnit", &(name.to_string(), "replace"))?;
200205
thread::sleep(Duration::from_millis(SLEEP_DURATION));
201-
self.get_unit(name)
206+
let mut service = self.get_unit(name)?;
207+
while service.state().active().ends_with("ing") {
208+
service = self.get_unit(name)?;
209+
thread::sleep(Duration::from_millis(100));
210+
}
211+
Ok(service)
202212
}
203213

204214
fn restart_service(&self, name: &str) -> Result<Service, Box<dyn std::error::Error>> {
205215
let proxy = self.manager_proxy()?;
206216
let _job: OwnedObjectPath = proxy.call("RestartUnit", &(name, "replace"))?;
207217
thread::sleep(Duration::from_millis(SLEEP_DURATION));
208-
self.get_unit(name)
218+
let mut service = self.get_unit(name)?;
219+
while service.state().active().ends_with("ing") {
220+
service = self.get_unit(name)?;
221+
thread::sleep(Duration::from_millis(100));
222+
}
223+
Ok(service)
209224
}
210225

211226
fn enable_service(&self, name: &str) -> Result<Service, Box<dyn std::error::Error>> {
@@ -224,6 +239,22 @@ impl ServiceRepository for SystemdServiceAdapter {
224239
self.get_unit(name)
225240
}
226241

242+
fn mask_service(&self, name: &str) -> Result<Service, Box<dyn std::error::Error>> {
243+
let proxy = self.manager_proxy()?;
244+
let _output: Vec<(String, String, String)> =
245+
proxy.call("MaskUnitFiles", &(vec![name], false, true))?;
246+
thread::sleep(Duration::from_millis(SLEEP_DURATION));
247+
self.get_unit(name)
248+
}
249+
250+
fn unmask_service(&self, name: &str) -> Result<Service, Box<dyn std::error::Error>> {
251+
let proxy = self.manager_proxy()?;
252+
let _output: Vec<(String, String, String)> =
253+
proxy.call("UnmaskUnitFiles", &(vec![name], false))?;
254+
thread::sleep(Duration::from_millis(SLEEP_DURATION));
255+
self.get_unit(name)
256+
}
257+
227258
fn reload_daemon(&self) -> Result<(), Box<dyn std::error::Error>> {
228259
let proxy = self.manager_proxy()?;
229260
proxy.call::<&str, (), ()>("Reload", &())?;

src/terminal/app.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::usecases::services_manager::ServicesManager;
2424

2525
use super::components::details::ServiceDetails;
2626
use super::components::filter::{Filter, InputMode};
27-
use super::components::list::TableServices;
27+
use super::components::list::{TableServices, ServiceAction};
2828
use super::components::log::ServiceLog;
2929

3030
#[derive(PartialEq)]
@@ -46,7 +46,8 @@ pub enum Actions {
4646
UpdateDetails,
4747
Filter(String),
4848
UpdateIgnoreListKeys(bool),
49-
EditCurrentService
49+
EditCurrentService,
50+
ServiceAction(ServiceAction)
5051
}
5152

5253
pub enum AppEvent {
@@ -174,6 +175,9 @@ fn spawn_key_event_listener(&self) {
174175
details.on_key_event(key);
175176
}
176177
},
178+
AppEvent::Action(Actions::ServiceAction(action)) => {
179+
table_service.act_on_selected_service(action);
180+
}
177181
AppEvent::Action(Actions::UpdateIgnoreListKeys(bool)) => {
178182
table_service.set_ignore_key_events(bool);
179183
}

src/terminal/components/list.rs

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ pub enum ServiceAction {
5858
Enable,
5959
Disable,
6060
RefreshAll,
61-
ToggleFilter
61+
ToggleFilter,
62+
ToggleMask
6263
}
6364

6465
pub struct TableServices {
@@ -219,6 +220,54 @@ impl TableServices {
219220
return;
220221
}
221222

223+
self.set_ignore_key_events(true);
224+
225+
match key.code {
226+
KeyCode::Char('r') => {
227+
self.sender.send(AppEvent::Action(Actions::ServiceAction(ServiceAction::Restart))).unwrap();
228+
return;
229+
}
230+
KeyCode::Char('s') => {
231+
self.sender.send(AppEvent::Action(Actions::ServiceAction(ServiceAction::Start))).unwrap();
232+
return;
233+
}
234+
KeyCode::Char('x') => {
235+
self.sender.send(AppEvent::Action(Actions::ServiceAction(ServiceAction::Stop))).unwrap();
236+
return;
237+
}
238+
KeyCode::Char('e') => {
239+
self.sender.send(AppEvent::Action(Actions::ServiceAction(ServiceAction::Enable))).unwrap();
240+
return;
241+
}
242+
KeyCode::Char('d') => {
243+
self.sender.send(AppEvent::Action(Actions::ServiceAction(ServiceAction::Disable))).unwrap();
244+
return;
245+
}
246+
KeyCode::Char('u') => {
247+
self.sender.send(AppEvent::Action(Actions::ServiceAction(ServiceAction::RefreshAll))).unwrap();
248+
return;
249+
}
250+
KeyCode::Char('v') => {
251+
self.sender.send(AppEvent::Action(Actions::GoLog)).unwrap();
252+
return;
253+
}
254+
KeyCode::Char('f') => {
255+
self.sender.send(AppEvent::Action(Actions::ServiceAction(ServiceAction::ToggleFilter))).unwrap();
256+
return;
257+
}
258+
KeyCode::Char('c') => {
259+
self.sender.send(AppEvent::Action(Actions::GoDetails)).unwrap();
260+
return;
261+
}
262+
KeyCode::Char('m') => {
263+
self.sender.send(AppEvent::Action(Actions::ServiceAction(ServiceAction::ToggleMask))).unwrap();
264+
return;
265+
}
266+
_ => {}
267+
}
268+
269+
self.set_ignore_key_events(false);
270+
222271
let up_keys = [KeyCode::Up, KeyCode::Char('k')];
223272
let down_keys = [KeyCode::Down, KeyCode::Char('j')];
224273

@@ -227,17 +276,6 @@ impl TableServices {
227276
code if up_keys.contains(&code) => self.select_previous(),
228277
KeyCode::PageDown => self.select_page_down(),
229278
KeyCode::PageUp => self.select_page_up(),
230-
KeyCode::Char('r') => self.act_on_selected_service(ServiceAction::Restart),
231-
KeyCode::Char('s') => self.act_on_selected_service(ServiceAction::Start),
232-
KeyCode::Char('e') => self.act_on_selected_service(ServiceAction::Enable),
233-
KeyCode::Char('d') => self.act_on_selected_service(ServiceAction::Disable),
234-
KeyCode::Char('u') => self.act_on_selected_service(ServiceAction::RefreshAll),
235-
KeyCode::Char('x') => self.act_on_selected_service(ServiceAction::Stop),
236-
KeyCode::Char('v') => self.sender.send(AppEvent::Action(Actions::GoLog)).unwrap(),
237-
KeyCode::Char('f') => self.act_on_selected_service(ServiceAction::ToggleFilter),
238-
KeyCode::Char('c') => {
239-
self.sender.send(AppEvent::Action(Actions::GoDetails)).unwrap();
240-
}
241279
_ => {}
242280
}
243281
}
@@ -298,11 +336,20 @@ impl TableServices {
298336
}
299337
}
300338

301-
fn act_on_selected_service(&mut self, action: ServiceAction) {
339+
pub fn act_on_selected_service(&mut self, action: ServiceAction) {
302340
if let Some(service) = self.get_selected_service() {
303341
let binding_usecase = self.usecase.clone();
304342
let usecase = binding_usecase.borrow();
305343
match action {
344+
ServiceAction::ToggleMask => {
345+
match service.state().file() {
346+
"masked" => self.handle_service_result(usecase.unmask_service(service)),
347+
"masked-runtime" => self.handle_service_result(usecase.unmask_service(service)),
348+
_ => self.handle_service_result(usecase.mask_service(service)),
349+
}
350+
self.fetch_services();
351+
self.fetch_and_refresh(self.old_filter_text.clone());
352+
},
306353
ServiceAction::Start => self.handle_service_result(usecase.start_service(service)),
307354
ServiceAction::Stop => self.handle_service_result(usecase.stop_service(service)),
308355
ServiceAction::Restart => self.handle_service_result(usecase.restart_service(service)),
@@ -319,6 +366,7 @@ impl TableServices {
319366
},
320367
}
321368
}
369+
self.set_ignore_key_events(false);
322370
}
323371

324372
fn handle_service_result(&mut self, result: Result<Service, Box<dyn Error>>) {
@@ -348,7 +396,7 @@ impl TableServices {
348396
)));
349397

350398
help_text.push(Line::from(
351-
"Navigate: ↑/↓ | Switch tab: ←/→ | Toggle Filter: f | Start: s | Stop: x | Restart: r | Enable: e | Disable: d | Refresh all: u | Log: v | Unit File: c"
399+
"Navigate: ↑/↓ | Switch tab: ←/→ | List all: f | Start: s | Stop: x | Restart: r | Enable: e | Disable: d | Mask/Unmask: m | Refresh list: u | Log: v | Unit File: c"
352400
));
353401
}
354402

src/usecases/services_manager.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ impl ServicesManager {
3939
self.repository.reload_daemon()?;
4040
Ok(service)
4141
}
42+
43+
pub fn mask_service(&self, service: &Service) -> Result<Service, Box<dyn Error>> {
44+
let service = self.repository.mask_service(service.name())?;
45+
Ok(service)
46+
}
47+
48+
pub fn unmask_service(&self, service: &Service) -> Result<Service, Box<dyn Error>> {
49+
let service = self.repository.unmask_service(service.name())?;
50+
Ok(service)
51+
}
4252

4353
pub fn list_services(&self, filter: bool) -> Result<Vec<Service>, Box<dyn Error>> {
4454
let mut all = Vec::new();

0 commit comments

Comments
 (0)