Files
Genarrative/apps/desktop-shell/src-tauri/src/host_bridge/badge.rs
T
kdletters 6a686e6ed8 收口桌面壳角标诊断日志
桌面壳角标失败只记录固定阶段标签

扩展桌面壳配置门禁禁止角标日志输出 Tauri 错误细节

补充宿主壳方案和共享决策中的角标诊断边界
2026-06-21 03:29:31 +08:00

118 lines
3.6 KiB
Rust

use crate::host_bridge::protocol::{failed, ok, HostBridgeRequest, HostBridgeResponse};
use serde_json::json;
use serde_json::Value;
use tauri::Manager;
const BADGE_COUNT_MAX: i64 = 99999;
fn badge_count_payload(request: &HostBridgeRequest) -> Result<Option<i64>, HostBridgeResponse> {
let count = request
.payload
.as_ref()
.and_then(|value| value.get("count"))
.and_then(Value::as_i64)
.ok_or_else(|| {
failed(
request.id.clone(),
"invalid_request",
"count must be an integer between 0 and 99999",
)
})?;
if !(0..=BADGE_COUNT_MAX).contains(&count) {
return Err(failed(
request.id.clone(),
"invalid_request",
"count must be an integer between 0 and 99999",
));
}
Ok(if count == 0 { None } else { Some(count) })
}
pub(crate) fn set_desktop_app_badge_count(
app: &tauri::AppHandle,
request: &HostBridgeRequest,
) -> HostBridgeResponse {
let count = match badge_count_payload(request) {
Ok(count) => count,
Err(response) => return response,
};
let Some(window) = app.get_webview_window("main") else {
log_desktop_badge_failure("window");
return badge_unavailable_response(request);
};
match window.set_badge_count(count) {
Ok(()) => ok(request.id.clone(), json!(true)),
Err(_error) => {
log_desktop_badge_failure("set");
badge_unavailable_response(request)
}
}
}
fn badge_unavailable_response(request: &HostBridgeRequest) -> HostBridgeResponse {
failed(request.id.clone(), "host_error", "badge unavailable")
}
fn log_desktop_badge_failure(label: &str) -> bool {
eprintln!("desktop app badge failed for {label}");
false
}
#[cfg(test)]
mod tests {
use super::*;
use crate::host_bridge::protocol::request;
use serde_json::json;
#[test]
fn badge_count_payload_accepts_clear_and_positive_counts() {
let mut clear = request("app.setBadgeCount");
clear.payload = Some(json!({ "count": 0 }));
assert_eq!(badge_count_payload(&clear).expect("clear badge"), None);
let mut count = request("app.setBadgeCount");
count.payload = Some(json!({ "count": 12 }));
assert_eq!(badge_count_payload(&count).expect("badge count"), Some(12));
}
#[test]
fn badge_count_payload_rejects_invalid_counts() {
for count in [json!(-1), json!(1.5), json!(100000), json!("1")] {
let mut invalid = request("app.setBadgeCount");
invalid.payload = Some(json!({ "count": count }));
let response = badge_count_payload(&invalid).expect_err("invalid count");
let error = response.error.expect("error");
assert_eq!(error.code, "invalid_request");
assert_eq!(
error.message,
"count must be an integer between 0 and 99999"
);
}
}
#[test]
fn badge_unavailable_response_is_stable() {
let response = badge_unavailable_response(&request("app.setBadgeCount"));
assert!(!response.ok);
let error = response.error.expect("badge error");
assert_eq!(error.code, "host_error");
assert_eq!(error.message, "badge unavailable");
}
#[test]
fn badge_failures_are_logged_without_exposing_native_detail() {
assert!(!log_desktop_badge_failure("set"));
assert!(!log_desktop_badge_failure("window"));
}
#[test]
fn badge_failures_log_stable_label_only() {
assert!(!log_desktop_badge_failure("set"));
}
}