6a686e6ed8
桌面壳角标失败只记录固定阶段标签 扩展桌面壳配置门禁禁止角标日志输出 Tauri 错误细节 补充宿主壳方案和共享决策中的角标诊断边界
118 lines
3.6 KiB
Rust
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"));
|
|
}
|
|
}
|