refactor(omo): deduplicate OMO/OMO Slim via OmoVariant parameterization

Introduce OmoVariant struct with STANDARD/SLIM constants to eliminate
~250 lines of copy-pasted code across DAO, service, commands, and
frontend layers. Adding a new OMO variant now requires only a single
const declaration instead of duplicating ~400 lines.
This commit is contained in:
Jason
2026-02-19 21:11:58 +08:00
parent 8e219b5eb1
commit 1b71dc721c
10 changed files with 493 additions and 741 deletions
+9 -24
View File
@@ -55,38 +55,23 @@ impl Default for OmoGlobalConfig {
}
impl Database {
pub fn get_omo_global_config(&self) -> Result<OmoGlobalConfig, AppError> {
let json_str = self.get_setting("common_config_omo")?;
pub fn get_omo_global_config(&self, key: &str) -> Result<OmoGlobalConfig, AppError> {
let json_str = self.get_setting(key)?;
match json_str {
Some(s) => serde_json::from_str::<OmoGlobalConfig>(&s)
.map_err(|e| AppError::Config(format!("Failed to parse common_config_omo: {e}"))),
.map_err(|e| AppError::Config(format!("Failed to parse {key}: {e}"))),
None => Ok(OmoGlobalConfig::default()),
}
}
pub fn save_omo_global_config(&self, config: &OmoGlobalConfig) -> Result<(), AppError> {
pub fn save_omo_global_config(
&self,
key: &str,
config: &OmoGlobalConfig,
) -> Result<(), AppError> {
let json_str = serde_json::to_string(config)
.map_err(|e| AppError::Config(format!("JSON serialization failed: {e}")))?;
self.set_setting("common_config_omo", &json_str)?;
Ok(())
}
// ── OMO Slim global config ──────────────────────────────────
pub fn get_omo_slim_global_config(&self) -> Result<OmoGlobalConfig, AppError> {
let json_str = self.get_setting("common_config_omo_slim")?;
match json_str {
Some(s) => serde_json::from_str::<OmoGlobalConfig>(&s).map_err(|e| {
AppError::Config(format!("Failed to parse common_config_omo_slim: {e}"))
}),
None => Ok(OmoGlobalConfig::default()),
}
}
pub fn save_omo_slim_global_config(&self, config: &OmoGlobalConfig) -> Result<(), AppError> {
let json_str = serde_json::to_string(config)
.map_err(|e| AppError::Config(format!("JSON serialization failed: {e}")))?;
self.set_setting("common_config_omo_slim", &json_str)?;
self.set_setting(key, &json_str)?;
Ok(())
}
}
+21 -141
View File
@@ -364,25 +364,26 @@ impl Database {
&self,
app_type: &str,
provider_id: &str,
category: &str,
) -> Result<(), AppError> {
let mut conn = lock_conn!(self.conn);
let tx = conn
.transaction()
.map_err(|e| AppError::Database(e.to_string()))?;
tx.execute(
"UPDATE providers SET is_current = 0 WHERE app_type = ?1 AND category = 'omo'",
params![app_type],
"UPDATE providers SET is_current = 0 WHERE app_type = ?1 AND category = ?2",
params![app_type, category],
)
.map_err(|e| AppError::Database(e.to_string()))?;
let updated = tx
.execute(
"UPDATE providers SET is_current = 1 WHERE id = ?1 AND app_type = ?2 AND category = 'omo'",
params![provider_id, app_type],
)
"UPDATE providers SET is_current = 1 WHERE id = ?1 AND app_type = ?2 AND category = ?3",
params![provider_id, app_type, category],
)
.map_err(|e| AppError::Database(e.to_string()))?;
if updated != 1 {
return Err(AppError::Database(format!(
"Failed to set OMO provider current: provider '{provider_id}' not found in app '{app_type}'"
"Failed to set {category} provider current: provider '{provider_id}' not found in app '{app_type}'"
)));
}
tx.commit().map_err(|e| AppError::Database(e.to_string()))?;
@@ -393,12 +394,13 @@ impl Database {
&self,
app_type: &str,
provider_id: &str,
category: &str,
) -> Result<bool, AppError> {
let conn = lock_conn!(self.conn);
match conn.query_row(
"SELECT is_current FROM providers
WHERE id = ?1 AND app_type = ?2 AND category = 'omo'",
params![provider_id, app_type],
WHERE id = ?1 AND app_type = ?2 AND category = ?3",
params![provider_id, app_type, category],
|row| row.get(0),
) {
Ok(is_current) => Ok(is_current),
@@ -411,152 +413,30 @@ impl Database {
&self,
app_type: &str,
provider_id: &str,
category: &str,
) -> Result<(), AppError> {
let conn = lock_conn!(self.conn);
conn.execute(
"UPDATE providers SET is_current = 0
WHERE id = ?1 AND app_type = ?2 AND category = 'omo'",
params![provider_id, app_type],
WHERE id = ?1 AND app_type = ?2 AND category = ?3",
params![provider_id, app_type, category],
)
.map_err(|e| AppError::Database(e.to_string()))?;
Ok(())
}
pub fn get_current_omo_provider(&self, app_type: &str) -> Result<Option<Provider>, AppError> {
let conn = lock_conn!(self.conn);
let row_data: Result<OmoProviderRow, rusqlite::Error> = conn.query_row(
"SELECT id, name, settings_config, category, created_at, sort_index, notes, meta
FROM providers
WHERE app_type = ?1 AND category = 'omo' AND is_current = 1
LIMIT 1",
params![app_type],
|row| {
Ok((
row.get(0)?,
row.get(1)?,
row.get(2)?,
row.get(3)?,
row.get(4)?,
row.get(5)?,
row.get(6)?,
row.get(7)?,
))
},
);
let (id, name, settings_config_str, category, created_at, sort_index, notes, meta_str) =
match row_data {
Ok(v) => v,
Err(rusqlite::Error::QueryReturnedNoRows) => return Ok(None),
Err(e) => return Err(AppError::Database(e.to_string())),
};
let settings_config = serde_json::from_str(&settings_config_str).map_err(|e| {
AppError::Database(format!(
"Failed to parse OMO provider settings_config (provider_id={id}): {e}"
))
})?;
let meta: crate::provider::ProviderMeta = if meta_str.trim().is_empty() {
crate::provider::ProviderMeta::default()
} else {
serde_json::from_str(&meta_str).map_err(|e| {
AppError::Database(format!(
"Failed to parse OMO provider meta (provider_id={id}): {e}"
))
})?
};
Ok(Some(Provider {
id,
name,
settings_config,
website_url: None,
category,
created_at,
sort_index,
notes,
meta: Some(meta),
icon: None,
icon_color: None,
in_failover_queue: false,
}))
}
// ── OMO Slim provider management ────────────────────────────
pub fn set_omo_slim_provider_current(
&self,
app_type: &str,
provider_id: &str,
) -> Result<(), AppError> {
let mut conn = lock_conn!(self.conn);
let tx = conn
.transaction()
.map_err(|e| AppError::Database(e.to_string()))?;
tx.execute(
"UPDATE providers SET is_current = 0 WHERE app_type = ?1 AND category = 'omo-slim'",
params![app_type],
)
.map_err(|e| AppError::Database(e.to_string()))?;
let updated = tx
.execute(
"UPDATE providers SET is_current = 1 WHERE id = ?1 AND app_type = ?2 AND category = 'omo-slim'",
params![provider_id, app_type],
)
.map_err(|e| AppError::Database(e.to_string()))?;
if updated != 1 {
return Err(AppError::Database(format!(
"Failed to set OMO Slim provider current: provider '{provider_id}' not found in app '{app_type}'"
)));
}
tx.commit().map_err(|e| AppError::Database(e.to_string()))?;
Ok(())
}
pub fn is_omo_slim_provider_current(
&self,
app_type: &str,
provider_id: &str,
) -> Result<bool, AppError> {
let conn = lock_conn!(self.conn);
match conn.query_row(
"SELECT is_current FROM providers
WHERE id = ?1 AND app_type = ?2 AND category = 'omo-slim'",
params![provider_id, app_type],
|row| row.get(0),
) {
Ok(is_current) => Ok(is_current),
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(false),
Err(e) => Err(AppError::Database(e.to_string())),
}
}
pub fn clear_omo_slim_provider_current(
&self,
app_type: &str,
provider_id: &str,
) -> Result<(), AppError> {
let conn = lock_conn!(self.conn);
conn.execute(
"UPDATE providers SET is_current = 0
WHERE id = ?1 AND app_type = ?2 AND category = 'omo-slim'",
params![provider_id, app_type],
)
.map_err(|e| AppError::Database(e.to_string()))?;
Ok(())
}
pub fn get_current_omo_slim_provider(
pub fn get_current_omo_provider(
&self,
app_type: &str,
category: &str,
) -> Result<Option<Provider>, AppError> {
let conn = lock_conn!(self.conn);
let row_data: Result<OmoProviderRow, rusqlite::Error> = conn.query_row(
"SELECT id, name, settings_config, category, created_at, sort_index, notes, meta
FROM providers
WHERE app_type = ?1 AND category = 'omo-slim' AND is_current = 1
WHERE app_type = ?1 AND category = ?2 AND is_current = 1
LIMIT 1",
params![app_type],
params![app_type, category],
|row| {
Ok((
row.get(0)?,
@@ -571,7 +451,7 @@ impl Database {
},
);
let (id, name, settings_config_str, category, created_at, sort_index, notes, meta_str) =
let (id, name, settings_config_str, _row_category, created_at, sort_index, notes, meta_str) =
match row_data {
Ok(v) => v,
Err(rusqlite::Error::QueryReturnedNoRows) => return Ok(None),
@@ -580,7 +460,7 @@ impl Database {
let settings_config = serde_json::from_str(&settings_config_str).map_err(|e| {
AppError::Database(format!(
"Failed to parse OMO Slim provider settings_config (provider_id={id}): {e}"
"Failed to parse {category} provider settings_config (provider_id={id}): {e}"
))
})?;
let meta: crate::provider::ProviderMeta = if meta_str.trim().is_empty() {
@@ -588,7 +468,7 @@ impl Database {
} else {
serde_json::from_str(&meta_str).map_err(|e| {
AppError::Database(format!(
"Failed to parse OMO Slim provider meta (provider_id={id}): {e}"
"Failed to parse {category} provider meta (provider_id={id}): {e}"
))
})?
};
@@ -598,7 +478,7 @@ impl Database {
name,
settings_config,
website_url: None,
category,
category: Some(category.to_string()),
created_at,
sort_index,
notes,