diff --git a/packages/app-lib/src/state/settings.rs b/packages/app-lib/src/state/settings.rs index 13419ae..f40435e 100644 --- a/packages/app-lib/src/state/settings.rs +++ b/packages/app-lib/src/state/settings.rs @@ -181,6 +181,7 @@ pub struct Settings { pub migrated: bool, pub developer_mode: bool, + #[serde(deserialize_with = "deserialize_feature_flags")] pub feature_flags: HashMap, pub skipped_update: Option, @@ -222,6 +223,43 @@ pub enum FeatureFlag { AutoInstallDependencies, } +/// 反序列化 feature flags,遇到未知的 flag 名称时直接忽略,而不是报错。 +/// +/// 这样即使前端(或更新的版本)写入了当前后端不认识的 flag, +/// 旧版本也能正常读取设置,而不是整包失败导致启动器初始化崩溃。 +fn deserialize_feature_flags<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let raw = HashMap::::deserialize(deserializer)?; + Ok(filter_known_feature_flags(raw)) +} + +/// 从 JSON 字符串解析 feature flags,忽略未知名称。 +fn parse_feature_flags_json(value: &str) -> HashMap { + match serde_json::from_str::>(value) { + Ok(raw) => filter_known_feature_flags(raw), + Err(_) => HashMap::new(), + } +} + +/// 只保留能解析为 [`FeatureFlag`] 的条目,未知名称静默丢弃。 +fn filter_known_feature_flags( + raw: HashMap, +) -> HashMap { + let mut flags = HashMap::with_capacity(raw.len()); + for (key, value) in raw { + if let Ok(flag) = + serde_json::from_value::(serde_json::Value::String(key)) + { + flags.insert(flag, value); + } + } + flags +} + impl Settings { const CURRENT_VERSION: usize = 3; @@ -384,8 +422,8 @@ impl Settings { migrated: res.migrated == 1, feature_flags: res .feature_flags - .as_ref() - .and_then(|x| serde_json::from_str(x).ok()) + .as_deref() + .map(parse_feature_flags_json) .unwrap_or_default(), skipped_update: res.skipped_update, pending_update_toast_for_version: res