mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-05-28 09:10:18 +08:00
feat(providers): auto-import OpenCode/OpenClaw live providers on startup
Drops the friction of clicking the manual "Import current config" button for OpenCode and OpenClaw — they now match the auto-import behavior the previous commit added for Claude/Codex/Gemini. - New "1.6." startup block in lib.rs runs both import_opencode_providers_from_live and import_openclaw_providers_from_live on every launch. The functions are id-keyed and idempotent, so re-running just picks up new providers added externally to the live JSON files. - Both functions now use a new Database::get_provider_ids() helper (HashSet<String> from a single SELECT id-only query) instead of get_all_providers(), avoiding the N+1 endpoint sub-queries that would otherwise hit the startup hot path on every launch.
This commit is contained in:
@@ -3,7 +3,7 @@ use crate::error::AppError;
|
||||
use crate::provider::{Provider, ProviderMeta};
|
||||
use indexmap::IndexMap;
|
||||
use rusqlite::params;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
type OmoProviderRow = (
|
||||
String,
|
||||
@@ -502,6 +502,25 @@ impl Database {
|
||||
}))
|
||||
}
|
||||
|
||||
/// 仅获取指定 app 下所有 provider 的 id 集合。
|
||||
///
|
||||
/// 比 `get_all_providers` 轻量得多:只读 id 列、无 endpoint 子查询。
|
||||
/// 用于只需要做存在性检查的场景(如 additive 模式的 live 同步去重)。
|
||||
pub fn get_provider_ids(&self, app_type: &str) -> Result<HashSet<String>, AppError> {
|
||||
let conn = lock_conn!(self.conn);
|
||||
let mut stmt = conn
|
||||
.prepare("SELECT id FROM providers WHERE app_type = ?1")
|
||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
let rows = stmt
|
||||
.query_map(params![app_type], |row| row.get::<_, String>(0))
|
||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
let mut ids = HashSet::new();
|
||||
for row in rows {
|
||||
ids.insert(row.map_err(|e| AppError::Database(e.to_string()))?);
|
||||
}
|
||||
Ok(ids)
|
||||
}
|
||||
|
||||
/// 判断指定 app 下是否存在非官方种子的供应商。
|
||||
///
|
||||
/// 比 `get_all_providers` 轻量得多:只读 id 列、无 endpoint 子查询、首条命中即返回。
|
||||
|
||||
@@ -502,6 +502,30 @@ pub fn run() {
|
||||
Err(e) => log::warn!("✗ Failed to seed official providers: {e}"),
|
||||
}
|
||||
|
||||
// 1.6. 自动同步 OpenCode / OpenClaw 的 live providers 到数据库
|
||||
//
|
||||
// additive 模式(OpenCode / OpenClaw)的 import 函数本身按 id 幂等,
|
||||
// 已有的 provider 会被跳过,所以每次启动都跑是安全的——既保证新装
|
||||
// 用户开箱可见 live 中的供应商,也让外部修改的 live 文件能在重启
|
||||
// 后同步到数据库(与之前依赖前端"导入当前配置"按钮手动触发不同)。
|
||||
//
|
||||
// 底层 read_*_config 在文件不存在时返回默认空配置,因此新装且无
|
||||
// live 文件的用户走 Ok(0) 路径,不会产生错误日志噪音。
|
||||
match crate::services::provider::import_opencode_providers_from_live(&app_state) {
|
||||
Ok(count) if count > 0 => {
|
||||
log::info!("✓ Imported {count} OpenCode provider(s) from live config");
|
||||
}
|
||||
Ok(_) => log::debug!("○ No new OpenCode providers to import"),
|
||||
Err(e) => log::warn!("✗ Failed to import OpenCode providers: {e}"),
|
||||
}
|
||||
match crate::services::provider::import_openclaw_providers_from_live(&app_state) {
|
||||
Ok(count) if count > 0 => {
|
||||
log::info!("✓ Imported {count} OpenClaw provider(s) from live config");
|
||||
}
|
||||
Ok(_) => log::debug!("○ No new OpenClaw providers to import"),
|
||||
Err(e) => log::warn!("✗ Failed to import OpenClaw providers: {e}"),
|
||||
}
|
||||
|
||||
// 2. OMO 配置导入(当数据库中无 OMO provider 时,从本地文件导入)
|
||||
{
|
||||
let has_omo = app_state
|
||||
|
||||
@@ -1209,11 +1209,11 @@ pub fn import_opencode_providers_from_live(state: &AppState) -> Result<usize, Ap
|
||||
}
|
||||
|
||||
let mut imported = 0;
|
||||
let existing = state.db.get_all_providers("opencode")?;
|
||||
let existing_ids = state.db.get_provider_ids("opencode")?;
|
||||
|
||||
for (id, config) in providers {
|
||||
// Skip if already exists in database
|
||||
if existing.contains_key(&id) {
|
||||
if existing_ids.contains(&id) {
|
||||
log::debug!("OpenCode provider '{id}' already exists in database, skipping");
|
||||
continue;
|
||||
}
|
||||
@@ -1266,7 +1266,7 @@ pub fn import_openclaw_providers_from_live(state: &AppState) -> Result<usize, Ap
|
||||
}
|
||||
|
||||
let mut imported = 0;
|
||||
let existing = state.db.get_all_providers("openclaw")?;
|
||||
let existing_ids = state.db.get_provider_ids("openclaw")?;
|
||||
|
||||
for (id, config) in providers {
|
||||
// Validate: skip entries with empty id or no models
|
||||
@@ -1280,7 +1280,7 @@ pub fn import_openclaw_providers_from_live(state: &AppState) -> Result<usize, Ap
|
||||
}
|
||||
|
||||
// Skip if already exists in database
|
||||
if existing.contains_key(&id) {
|
||||
if existing_ids.contains(&id) {
|
||||
log::debug!("OpenClaw provider '{id}' already exists in database, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user