cc_switch_lib/database/dao/
failover.rs1use crate::database::{lock_conn, Database};
6use crate::error::AppError;
7use crate::provider::Provider;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12#[serde(rename_all = "camelCase")]
13pub struct FailoverQueueItem {
14 pub provider_id: String,
15 pub provider_name: String,
16 pub sort_index: Option<usize>,
17}
18
19impl Database {
20 pub fn get_failover_queue(&self, app_type: &str) -> Result<Vec<FailoverQueueItem>, AppError> {
22 let conn = lock_conn!(self.conn);
23
24 let mut stmt = conn
25 .prepare(
26 "SELECT id, name, sort_index
27 FROM providers
28 WHERE app_type = ?1 AND in_failover_queue = 1
29 ORDER BY COALESCE(sort_index, 999999), id ASC",
30 )
31 .map_err(|e| AppError::Database(e.to_string()))?;
32
33 let items = stmt
34 .query_map([app_type], |row| {
35 Ok(FailoverQueueItem {
36 provider_id: row.get(0)?,
37 provider_name: row.get(1)?,
38 sort_index: row.get(2)?,
39 })
40 })
41 .map_err(|e| AppError::Database(e.to_string()))?
42 .collect::<Result<Vec<_>, _>>()
43 .map_err(|e| AppError::Database(e.to_string()))?;
44
45 Ok(items)
46 }
47
48 pub fn get_failover_providers(&self, app_type: &str) -> Result<Vec<Provider>, AppError> {
50 let all_providers = self.get_all_providers(app_type)?;
51
52 let result: Vec<Provider> = all_providers
53 .into_values()
54 .filter(|p| p.in_failover_queue)
55 .collect();
56
57 Ok(result)
58 }
59
60 pub fn add_to_failover_queue(&self, app_type: &str, provider_id: &str) -> Result<(), AppError> {
62 let conn = lock_conn!(self.conn);
63
64 conn.execute(
65 "UPDATE providers SET in_failover_queue = 1 WHERE id = ?1 AND app_type = ?2",
66 rusqlite::params![provider_id, app_type],
67 )
68 .map_err(|e| AppError::Database(e.to_string()))?;
69
70 Ok(())
71 }
72
73 pub fn remove_from_failover_queue(
75 &self,
76 app_type: &str,
77 provider_id: &str,
78 ) -> Result<(), AppError> {
79 let conn = lock_conn!(self.conn);
80
81 conn.execute(
83 "UPDATE providers SET in_failover_queue = 0 WHERE id = ?1 AND app_type = ?2",
84 rusqlite::params![provider_id, app_type],
85 )
86 .map_err(|e| AppError::Database(e.to_string()))?;
87
88 conn.execute(
90 "DELETE FROM provider_health WHERE provider_id = ?1 AND app_type = ?2",
91 rusqlite::params![provider_id, app_type],
92 )
93 .map_err(|e| AppError::Database(e.to_string()))?;
94
95 log::info!("已从故障转移队列移除供应商 {provider_id} ({app_type}), 并清除其健康状态");
96
97 Ok(())
98 }
99
100 pub fn clear_failover_queue(&self, app_type: &str) -> Result<(), AppError> {
102 let conn = lock_conn!(self.conn);
103
104 conn.execute(
105 "UPDATE providers SET in_failover_queue = 0 WHERE app_type = ?1",
106 [app_type],
107 )
108 .map_err(|e| AppError::Database(e.to_string()))?;
109
110 Ok(())
111 }
112
113 pub fn is_in_failover_queue(
115 &self,
116 app_type: &str,
117 provider_id: &str,
118 ) -> Result<bool, AppError> {
119 let conn = lock_conn!(self.conn);
120
121 let in_queue: bool = conn
122 .query_row(
123 "SELECT in_failover_queue FROM providers WHERE id = ?1 AND app_type = ?2",
124 rusqlite::params![provider_id, app_type],
125 |row| row.get(0),
126 )
127 .unwrap_or(false);
128
129 Ok(in_queue)
130 }
131
132 pub fn get_available_providers_for_failover(
134 &self,
135 app_type: &str,
136 ) -> Result<Vec<Provider>, AppError> {
137 let all_providers = self.get_all_providers(app_type)?;
138
139 let available: Vec<Provider> = all_providers
140 .into_values()
141 .filter(|p| !p.in_failover_queue)
142 .collect();
143
144 Ok(available)
145 }
146}