Skip to content

Commit 4205b95

Browse files
committed
handle module thread errors
1 parent 7c45463 commit 4205b95

File tree

5 files changed

+85
-8
lines changed

5 files changed

+85
-8
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "baru"
3-
version = "0.4.0"
3+
version = "0.4.1"
44
description = "A simple system monitor for WM statusbar"
55
authors = ["pierre <[email protected]>"]
66
edition = "2021"

baru.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ tick: 100
4646
#
4747
pulse_tick: 100
4848

49+
# failed_icon: String, default: ✗
50+
#
51+
# The icon printed when a module has failed.
52+
#
53+
failed_icon: ''
4954

5055
# Each module take a "format" option.
5156
# This option is a string and the following markups will be replaced respectively by the value and the label of the module:

src/lib.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
pub mod cli;
66
mod error;
7+
mod http;
78
mod module;
89
mod modules;
910
mod netlink;
1011
mod pulse;
1112
pub mod trace;
1213
pub mod util;
13-
mod http;
1414

1515
use anyhow::{anyhow, Result};
1616
use error::Error;
@@ -43,6 +43,7 @@ pub struct ModuleMsg(char, Option<String>, Option<String>);
4343
pub struct Config {
4444
format: String,
4545
pub tick: Option<u32>,
46+
failed_icon: Option<String>,
4647
pulse_tick: Option<u32>,
4748
battery: Option<BatteryConfig>,
4849
brightness: Option<BrightnessConfig>,
@@ -87,25 +88,26 @@ impl<'a> Baru<'a> {
8788
}
8889

8990
#[instrument(skip_all)]
90-
pub fn start(&self) -> Result<()> {
91+
pub fn start(&mut self) -> Result<()> {
9192
// check if any module needs pulse, i.e. sound or mic modules
9293
let need_pulse = self.modules.iter().any(|m| m.key == 's' || m.key == 'i');
9394
if need_pulse {
9495
pulse::init(self.config);
9596
}
96-
for data in &self.modules {
97+
for data in &mut self.modules {
9798
let builder = thread::Builder::new().name(format!("mod_{}", data.module.name()));
9899
let cloned_m_conf = self.config.clone();
99100
let tx1 = mpsc::Sender::clone(&self.channel.0);
100101
let run = data.module.run_fn();
101102
let key = data.key;
102103
let c_name = data.module.name().to_string();
103-
builder.spawn(move || -> Result<(), Error> {
104-
info!("[{}] module starting", c_name);
104+
let handle = builder.spawn(move || -> Result<(), Error> {
105105
run(key, cloned_m_conf, tx1)
106106
.inspect_err(|e| error!("[{}] module failed: {}", c_name, e))?;
107107
Ok(())
108108
})?;
109+
data.start(handle);
110+
info!("[{}] module started", data.module.name());
109111
}
110112
Ok(())
111113
}
@@ -124,6 +126,7 @@ impl<'a> Baru<'a> {
124126
pub fn update(&mut self) -> Result<()> {
125127
let messages: Vec<ModuleMsg> = self.channel.1.try_iter().collect();
126128
for module in &mut self.modules {
129+
module.update_state().ok();
127130
let mut iter = messages.iter().rev();
128131
let message = iter.find(|v| v.0 == module.key);
129132
if let Some(value) = message {

src/module.rs

+70-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,14 @@ use crate::modules::wired::Wired;
1717
use crate::modules::wireless::Wireless;
1818
use crate::Config;
1919
use crate::ModuleMsg;
20+
21+
use anyhow::{anyhow, Result};
2022
use std::convert::TryFrom;
2123
use std::sync::mpsc::Sender;
24+
use std::thread::JoinHandle;
25+
use tracing::{error, info, instrument};
26+
27+
const MODULE_FAILED_ICON: &str = "✗";
2228

2329
pub type RunPtr = fn(char, Config, Sender<ModuleMsg>) -> Result<(), Error>;
2430

@@ -137,19 +143,39 @@ impl<'a> Bar for Module<'a> {
137143
}
138144
}
139145

146+
#[derive(Debug, Clone)]
147+
pub enum ModuleState {
148+
NotStarted,
149+
Running,
150+
/// Module's `run` function returned without errors
151+
Finished,
152+
/// Module's `run` function returned an error or panicked
153+
Failed,
154+
}
155+
140156
#[derive(Debug)]
141157
pub struct ModuleData<'a> {
142158
pub key: char,
143159
pub module: Module<'a>,
144160
data: Option<String>,
161+
state: ModuleState,
162+
handle: Option<JoinHandle<Result<(), Error>>>,
163+
failed_placeholder: String,
145164
}
146165

147166
impl<'a> ModuleData<'a> {
148-
pub fn new(key: char, config: &'a Config) -> Result<Self, Error> {
167+
pub fn new(key: char, config: &'a Config) -> Result<Self> {
149168
Ok(ModuleData {
150169
key,
151170
module: Module::try_from((key, config))?,
152171
data: None,
172+
state: ModuleState::NotStarted,
173+
handle: None,
174+
failed_placeholder: config
175+
.failed_icon
176+
.as_ref()
177+
.map(|icon| format!("{}:{}", &key, icon))
178+
.unwrap_or_else(|| format!("{}:{}", &key, MODULE_FAILED_ICON)),
153179
})
154180
}
155181

@@ -167,10 +193,53 @@ impl<'a> ModuleData<'a> {
167193
}
168194

169195
pub fn output(&self) -> &str {
196+
if matches!(self.state, ModuleState::Failed) {
197+
return &self.failed_placeholder;
198+
}
199+
170200
if let Some(data) = &self.data {
171201
data
172202
} else {
173203
self.module.placeholder()
174204
}
175205
}
206+
207+
pub fn start(&mut self, handle: JoinHandle<Result<(), Error>>) {
208+
self.handle = Some(handle);
209+
self.state = ModuleState::Running;
210+
}
211+
212+
#[instrument(skip_all)]
213+
pub fn update_state(&mut self) -> Result<()> {
214+
let Some(handle) = &self.handle else {
215+
return Ok(());
216+
};
217+
if !handle.is_finished() {
218+
return Ok(());
219+
}
220+
221+
// module thread has finished for some reason, join it
222+
// and update the state accordingly
223+
self.state = match self
224+
.handle
225+
.take()
226+
.ok_or(anyhow!("failed to unwrap handle"))?
227+
.join()
228+
{
229+
Ok(Ok(_)) => {
230+
info!("[{}] module finished", self.module.name());
231+
ModuleState::Finished
232+
}
233+
Ok(Err(e)) => {
234+
error!("[{}] module failed: {}", self.module.name(), e);
235+
ModuleState::Failed
236+
}
237+
Err(_) => {
238+
let msg = format!("[{}] module panicked", self.module.name());
239+
error!("{}", &msg);
240+
ModuleState::Failed
241+
}
242+
};
243+
Ok(())
244+
}
176245
}

0 commit comments

Comments
 (0)