Fix 18 issues flagged in audit + bump to v0.6.2
P1-A: normalizer derives `online` from rtnetlink event kind (link.up/down,
route.default.changed, address.added/removed) so bread.network.connected
fires correctly on all systems using rtnetlink.
P1-B: stream_events consumes the subscribe ack before the event loop so the
first line is not printed as garbage.
P1-C: UPowerAdapter::probe() validates D-Bus synchronously before committing;
the sysfs fallback now actually triggers when D-Bus is unavailable.
P2-A: profile.list returns the full profile state (active + history) instead
of the always-empty profiles map.
P2-B: profile history capped at 50 entries in both StateCommand and
apply_event_to_state to prevent unbounded growth.
P2-C: RtnetlinkAdapter::new() no longer spawns an orphaned tokio task;
it validates availability by constructing and immediately dropping the
connection tuple.
P2-D: Lua-side hyprland_request_socket() logs a warn when multiple
Hyprland instances are found, matching the adapter-side behaviour.
P2-E: Malformed JSON from an IPC client returns an error response and
continues rather than closing the entire connection.
P3-A: Remove the `ends_with(".*")` prefix-match shortcut from both the
subscription table and the IPC event filter. `bread.*` now means
one segment (matching documented API semantics: `* = one segment`).
Tests updated accordingly.
P4-A: Remove unused `git2` and `glob` workspace dependencies (left over
from bread-sync extraction).
P4-B: breadd dev-dependency `tempfile` declared via workspace = true.
P4-C: Remove unreachable XDG_CONFIG_HOME branch in modules_dir(); dirs
already reads that var internally before returning None.
P4-D: Delete duplicate send_request_with_stream(); print_doctor() now
uses socket.exists() + send_request() directly.
P5-A: release.yml drops `--lib` from cargo test so integration tests run
in the release gate.
P6-A: bluetooth_spawn / bluetooth_query replace expect() on tokio runtime
construction with error logging / error propagation.
P6-B: Spin loops in lua/mod.rs add std:🧵:yield_now() after the
PAUSE hint to reduce CPU burn under sustained RwLock contention.
P6-C: All Mutex::lock().expect("... poisoned") in lua/mod.rs replaced with
unwrap_or_else(|e| e.into_inner()) for poison recovery.
P7-B: bread.system.startup event moved from main.rs into ipc::Server::serve()
so it fires after the socket is bound (smaller race window for early
subscribers).
This commit is contained in:
parent
0f3136ca8d
commit
3115a4230b
17 changed files with 146 additions and 136 deletions
|
|
@ -382,22 +382,39 @@ impl EventNormalizer {
|
|||
}
|
||||
|
||||
fn normalize_network(&self, raw: &RawEvent) -> Vec<BreadEvent> {
|
||||
let online = raw
|
||||
.payload
|
||||
.get("online")
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(false);
|
||||
// The sysfs NetworkAdapter puts `online: bool` directly in the payload.
|
||||
// The rtnetlink adapter omits it; derive connectivity from the event kind instead.
|
||||
let online = if let Some(v) = raw.payload.get("online").and_then(Value::as_bool) {
|
||||
v
|
||||
} else {
|
||||
match raw.kind.as_str() {
|
||||
"link.up" | "address.added" => true,
|
||||
"link.down" | "address.removed" => false,
|
||||
"route.default.changed" => raw
|
||||
.payload
|
||||
.get("gateway")
|
||||
.map(|v| !v.is_null())
|
||||
.unwrap_or(false),
|
||||
_ => return vec![],
|
||||
}
|
||||
};
|
||||
|
||||
let name = if online {
|
||||
"bread.network.connected"
|
||||
} else {
|
||||
"bread.network.disconnected"
|
||||
};
|
||||
|
||||
let mut data = raw.payload.clone();
|
||||
if let Some(obj) = data.as_object_mut() {
|
||||
obj.insert("online".to_string(), Value::Bool(online));
|
||||
}
|
||||
|
||||
vec![BreadEvent {
|
||||
event: name.to_string(),
|
||||
timestamp: raw.timestamp,
|
||||
source: AdapterSource::Network,
|
||||
data: raw.payload.clone(),
|
||||
data,
|
||||
}]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -315,6 +315,9 @@ async fn handle_command(
|
|||
let mut guard = state.write().await;
|
||||
if guard.profile.active != name {
|
||||
let previous = guard.profile.active.clone();
|
||||
if guard.profile.history.len() >= 50 {
|
||||
guard.profile.history.remove(0);
|
||||
}
|
||||
guard.profile.history.push(previous);
|
||||
guard.profile.active = name;
|
||||
}
|
||||
|
|
@ -450,6 +453,9 @@ fn apply_event_to_state(state: &mut RuntimeState, event: &BreadEvent) {
|
|||
if let Some(name) = event.data.get("name").and_then(Value::as_str) {
|
||||
if state.profile.active != name {
|
||||
let previous = state.profile.active.clone();
|
||||
if state.profile.history.len() >= 50 {
|
||||
state.profile.history.remove(0);
|
||||
}
|
||||
state.profile.history.push(previous);
|
||||
state.profile.active = name.to_string();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,11 +67,6 @@ impl SubscriptionTable {
|
|||
}
|
||||
|
||||
fn matches_pattern(pattern: &str, event_name: &str) -> bool {
|
||||
if pattern.ends_with(".*") {
|
||||
let prefix = &pattern[..pattern.len() - 1];
|
||||
return event_name.starts_with(prefix);
|
||||
}
|
||||
|
||||
if let Some(prefix) = pattern.strip_suffix(".**") {
|
||||
if event_name == prefix {
|
||||
return true;
|
||||
|
|
@ -150,11 +145,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn single_segment_wildcard() {
|
||||
assert!(matches_pattern(
|
||||
assert!(matches_pattern("bread.device.*", "bread.device.foo"));
|
||||
assert!(!matches_pattern(
|
||||
"bread.device.*",
|
||||
"bread.device.dock.connected"
|
||||
));
|
||||
assert!(matches_pattern("bread.device.*", "bread.device.foo"));
|
||||
assert!(!matches_pattern("bread.device.*", "bread.device"));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue