feat: Rust refactor — full backend rewrite (Phases 1-6)

Phase 1-3: Scaffold + types + auth (JWT, Argon2, API keys)
Phase 4a: Admin API (sites/accounts/tokens/downstream-keys/settings)
Phase 5: Proxy core (/v1/chat, /v1/images, /v1/models)
Phase 6: ComfyUI proxy routes migrated

- 80+ source files, all cargo check + 18 tests green
- Drop-in compatible with Node.js API surface
This commit is contained in:
boos
2026-05-17 13:20:52 +08:00
parent ad0bb86e31
commit 7987833ba9
61 changed files with 3661 additions and 1 deletions
+11
View File
@@ -0,0 +1,11 @@
use sqlx::sqlite::{SqlitePool, SqlitePoolOptions};
pub mod models;
pub async fn create_pool(database_url: &str, max_connections: u32) -> anyhow::Result<SqlitePool> {
let pool = SqlitePoolOptions::new()
.max_connections(max_connections)
.connect(database_url)
.await?;
Ok(pool)
}
+45
View File
@@ -0,0 +1,45 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// Represents an account bound to a site.
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Account {
pub id: i64,
pub site_id: i64,
pub username: Option<String>,
pub access_token: String,
pub api_token: Option<String>,
pub balance: Option<f64>,
pub balance_used: Option<f64>,
pub quota: Option<f64>,
pub unit_cost: Option<f64>,
pub value_score: Option<f64>,
pub status: String,
pub checkin_enabled: Option<bool>,
pub last_checkin_at: Option<String>,
pub last_balance_refresh: Option<String>,
pub extra_config: Option<String>,
pub is_pinned: Option<bool>,
pub sort_order: Option<i64>,
pub oauth_provider: Option<String>,
pub oauth_account_key: Option<String>,
pub oauth_project_id: Option<String>,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
/// Represents an account token (from account_tokens table).
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct AccountToken {
pub id: i64,
pub account_id: i64,
pub name: String,
pub token: String,
pub source: Option<String>,
pub token_group: Option<String>,
pub value_status: String,
pub enabled: Option<bool>,
pub is_default: Option<bool>,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
@@ -0,0 +1,28 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// Represents a downstream API key for external consumers.
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct DownstreamApiKey {
pub id: i64,
pub name: String,
pub key: String,
pub description: Option<String>,
pub group_name: Option<String>,
pub tags: Option<String>,
pub enabled: Option<bool>,
pub expires_at: Option<String>,
pub max_cost: Option<f64>,
pub used_cost: Option<f64>,
pub max_requests: Option<i64>,
pub used_requests: Option<i64>,
pub supported_models: Option<String>,
pub allowed_route_ids: Option<String>,
pub site_weight_multipliers: Option<String>,
pub excluded_site_ids: Option<String>,
pub excluded_credential_refs: Option<String>,
pub last_used_at: Option<String>,
pub user_id: Option<i64>,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
+8
View File
@@ -0,0 +1,8 @@
// Database models
pub mod account;
pub mod downstream_api_key;
pub mod route_channel;
pub mod setting;
pub mod site;
pub mod token_route;
+27
View File
@@ -0,0 +1,27 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// Represents a route channel linking routes, accounts, and tokens.
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct RouteChannel {
pub id: i64,
pub route_id: i64,
pub account_id: i64,
pub token_id: Option<i64>,
pub oauth_route_unit_id: Option<i64>,
pub source_model: Option<String>,
pub priority: Option<i64>,
pub weight: Option<i64>,
pub enabled: Option<bool>,
pub manual_override: Option<bool>,
pub success_count: Option<i64>,
pub fail_count: Option<i64>,
pub total_latency_ms: Option<i64>,
pub total_cost: Option<f64>,
pub last_used_at: Option<String>,
pub last_selected_at: Option<String>,
pub last_fail_at: Option<String>,
pub consecutive_fail_count: i64,
pub cooldown_level: i64,
pub cooldown_until: Option<String>,
}
+9
View File
@@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// Represents a key-value setting.
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Setting {
pub key: String,
pub value: Option<String>,
}
+26
View File
@@ -0,0 +1,26 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// Represents a site (AI provider endpoint).
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Site {
pub id: i64,
pub name: String,
pub url: String,
pub platform: String,
pub status: String,
pub api_key: Option<String>,
pub proxy_url: Option<String>,
pub use_system_proxy: Option<bool>,
pub custom_headers: Option<String>,
pub external_checkin_url: Option<String>,
pub global_weight: Option<f64>,
pub post_refresh_probe_enabled: Option<bool>,
pub post_refresh_probe_model: Option<String>,
pub post_refresh_probe_scope: Option<String>,
pub post_refresh_probe_latency_threshold_ms: Option<i64>,
pub is_pinned: Option<bool>,
pub sort_order: Option<i64>,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
+19
View File
@@ -0,0 +1,19 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// Represents a token route (model routing rule).
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct TokenRoute {
pub id: i64,
pub model_pattern: String,
pub model_mapping: Option<String>,
pub display_name: Option<String>,
pub display_icon: Option<String>,
pub decision_snapshot: Option<String>,
pub decision_refreshed_at: Option<String>,
pub routing_strategy: Option<String>,
pub route_mode: Option<String>,
pub enabled: Option<bool>,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
+1
View File
@@ -0,0 +1 @@
// Database queries