2026-05-05 18:27:36 +08:00
|
|
|
use aether_data::{DataBackends, DataLayerError, DatabaseDriver};
|
2026-05-08 00:18:12 +08:00
|
|
|
use aether_runtime_state::RuntimeQueueStore;
|
|
|
|
|
use std::sync::Arc;
|
2026-04-04 01:40:24 +08:00
|
|
|
|
|
|
|
|
use super::{GatewayDataConfig, GatewayDataState, StoredSystemConfigEntry};
|
2026-03-31 19:19:04 +08:00
|
|
|
|
|
|
|
|
fn current_system_config_updated_at_unix_secs() -> u64 {
|
|
|
|
|
std::time::SystemTime::now()
|
|
|
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.as_secs()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl GatewayDataState {
|
|
|
|
|
pub(crate) fn disabled() -> Self {
|
|
|
|
|
Self::default()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn from_config(config: GatewayDataConfig) -> Result<Self, DataLayerError> {
|
|
|
|
|
if !config.is_enabled() {
|
|
|
|
|
return Ok(Self {
|
|
|
|
|
config,
|
|
|
|
|
backends: None,
|
|
|
|
|
auth_api_key_reader: None,
|
|
|
|
|
auth_api_key_writer: None,
|
|
|
|
|
auth_module_reader: None,
|
|
|
|
|
auth_module_writer: None,
|
|
|
|
|
announcement_reader: None,
|
|
|
|
|
announcement_writer: None,
|
|
|
|
|
management_token_reader: None,
|
|
|
|
|
management_token_writer: None,
|
|
|
|
|
oauth_provider_reader: None,
|
|
|
|
|
oauth_provider_writer: None,
|
|
|
|
|
proxy_node_reader: None,
|
|
|
|
|
proxy_node_writer: None,
|
|
|
|
|
billing_reader: None,
|
2026-05-09 21:19:29 +08:00
|
|
|
background_task_reader: None,
|
|
|
|
|
background_task_writer: None,
|
2026-03-31 19:19:04 +08:00
|
|
|
gemini_file_mapping_reader: None,
|
|
|
|
|
gemini_file_mapping_writer: None,
|
|
|
|
|
global_model_reader: None,
|
|
|
|
|
global_model_writer: None,
|
|
|
|
|
minimal_candidate_selection_reader: None,
|
|
|
|
|
request_candidate_reader: None,
|
|
|
|
|
request_candidate_writer: None,
|
|
|
|
|
provider_catalog_reader: None,
|
|
|
|
|
provider_catalog_writer: None,
|
2026-05-12 01:46:22 +08:00
|
|
|
pool_score_reader: None,
|
|
|
|
|
pool_score_writer: None,
|
2026-03-31 19:19:04 +08:00
|
|
|
provider_quota_reader: None,
|
|
|
|
|
provider_quota_writer: None,
|
2026-05-18 11:03:49 +08:00
|
|
|
routing_group_reader: None,
|
|
|
|
|
routing_group_writer: None,
|
2026-03-31 19:19:04 +08:00
|
|
|
usage_reader: None,
|
|
|
|
|
usage_writer: None,
|
|
|
|
|
user_reader: None,
|
|
|
|
|
user_preferences: None,
|
2026-05-08 00:18:12 +08:00
|
|
|
usage_worker_queue: None,
|
2026-03-31 19:19:04 +08:00
|
|
|
video_task_reader: None,
|
|
|
|
|
video_task_writer: None,
|
|
|
|
|
wallet_reader: None,
|
|
|
|
|
wallet_writer: None,
|
2026-04-05 20:23:16 +08:00
|
|
|
settlement_writer: None,
|
2026-03-31 19:19:04 +08:00
|
|
|
system_config_values: None,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let backends = DataBackends::from_config(config.to_data_layer_config())?;
|
|
|
|
|
let auth_api_key_reader = backends.read().auth_api_keys();
|
|
|
|
|
let auth_api_key_writer = backends.write().auth_api_keys();
|
|
|
|
|
let auth_module_reader = backends.read().auth_modules();
|
|
|
|
|
let auth_module_writer = backends.write().auth_modules();
|
|
|
|
|
let announcement_reader = backends.read().announcements();
|
|
|
|
|
let announcement_writer = backends.write().announcements();
|
|
|
|
|
let management_token_reader = backends.read().management_tokens();
|
|
|
|
|
let management_token_writer = backends.write().management_tokens();
|
|
|
|
|
let oauth_provider_reader = backends.read().oauth_providers();
|
|
|
|
|
let oauth_provider_writer = backends.write().oauth_providers();
|
|
|
|
|
let proxy_node_reader = backends.read().proxy_nodes();
|
|
|
|
|
let proxy_node_writer = backends.write().proxy_nodes();
|
|
|
|
|
let billing_reader = backends.read().billing();
|
2026-05-09 21:19:29 +08:00
|
|
|
let background_task_reader = backends.read().background_tasks();
|
|
|
|
|
let background_task_writer = backends.write().background_tasks();
|
2026-03-31 19:19:04 +08:00
|
|
|
let gemini_file_mapping_reader = backends.read().gemini_file_mappings();
|
|
|
|
|
let global_model_reader = backends.read().global_models();
|
|
|
|
|
let global_model_writer = backends.write().global_models();
|
|
|
|
|
let minimal_candidate_selection_reader = backends.read().minimal_candidate_selection();
|
|
|
|
|
let request_candidate_reader = backends.read().request_candidates();
|
|
|
|
|
let request_candidate_writer = backends.write().request_candidates();
|
|
|
|
|
let gemini_file_mapping_writer = backends.write().gemini_file_mappings();
|
|
|
|
|
let provider_catalog_reader = backends.read().provider_catalog();
|
|
|
|
|
let provider_catalog_writer = backends.write().provider_catalog();
|
2026-05-12 01:46:22 +08:00
|
|
|
let pool_score_reader = backends.read().pool_scores();
|
|
|
|
|
let pool_score_writer = backends.write().pool_scores();
|
2026-03-31 19:19:04 +08:00
|
|
|
let provider_quota_reader = backends.read().provider_quotas();
|
|
|
|
|
let provider_quota_writer = backends.write().provider_quotas();
|
2026-05-18 11:03:49 +08:00
|
|
|
let routing_group_reader = backends.read().routing_groups();
|
|
|
|
|
let routing_group_writer = backends.write().routing_groups();
|
2026-03-31 19:19:04 +08:00
|
|
|
let usage_reader = backends.read().usage();
|
|
|
|
|
let usage_writer = backends.write().usage();
|
|
|
|
|
let user_reader = backends.read().users();
|
2026-05-08 00:18:12 +08:00
|
|
|
let usage_worker_queue = None;
|
2026-03-31 19:19:04 +08:00
|
|
|
let video_task_reader = backends.read().video_tasks();
|
|
|
|
|
let video_task_writer = backends.write().video_tasks();
|
|
|
|
|
let wallet_reader = backends.read().wallets();
|
|
|
|
|
let wallet_writer = backends.write().wallets();
|
2026-04-05 20:23:16 +08:00
|
|
|
let settlement_writer = backends.write().settlement();
|
2026-03-31 19:19:04 +08:00
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
|
config,
|
|
|
|
|
backends: Some(backends),
|
|
|
|
|
auth_api_key_reader,
|
|
|
|
|
auth_api_key_writer,
|
|
|
|
|
auth_module_reader,
|
|
|
|
|
auth_module_writer,
|
|
|
|
|
announcement_reader,
|
|
|
|
|
announcement_writer,
|
|
|
|
|
management_token_reader,
|
|
|
|
|
management_token_writer,
|
|
|
|
|
oauth_provider_reader,
|
|
|
|
|
oauth_provider_writer,
|
|
|
|
|
proxy_node_reader,
|
|
|
|
|
proxy_node_writer,
|
|
|
|
|
billing_reader,
|
2026-05-09 21:19:29 +08:00
|
|
|
background_task_reader,
|
|
|
|
|
background_task_writer,
|
2026-03-31 19:19:04 +08:00
|
|
|
gemini_file_mapping_reader,
|
|
|
|
|
gemini_file_mapping_writer,
|
|
|
|
|
global_model_reader,
|
|
|
|
|
global_model_writer,
|
|
|
|
|
minimal_candidate_selection_reader,
|
|
|
|
|
request_candidate_reader,
|
|
|
|
|
request_candidate_writer,
|
|
|
|
|
provider_catalog_reader,
|
|
|
|
|
provider_catalog_writer,
|
2026-05-12 01:46:22 +08:00
|
|
|
pool_score_reader,
|
|
|
|
|
pool_score_writer,
|
2026-03-31 19:19:04 +08:00
|
|
|
provider_quota_reader,
|
|
|
|
|
provider_quota_writer,
|
2026-05-18 11:03:49 +08:00
|
|
|
routing_group_reader,
|
|
|
|
|
routing_group_writer,
|
2026-03-31 19:19:04 +08:00
|
|
|
usage_reader,
|
|
|
|
|
usage_writer,
|
|
|
|
|
user_reader,
|
|
|
|
|
user_preferences: None,
|
2026-05-08 00:18:12 +08:00
|
|
|
usage_worker_queue,
|
2026-03-31 19:19:04 +08:00
|
|
|
video_task_reader,
|
|
|
|
|
video_task_writer,
|
|
|
|
|
wallet_reader,
|
|
|
|
|
wallet_writer,
|
2026-04-05 20:23:16 +08:00
|
|
|
settlement_writer,
|
2026-03-31 19:19:04 +08:00
|
|
|
system_config_values: None,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_backends(&self) -> bool {
|
|
|
|
|
self.backends.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-08 00:18:12 +08:00
|
|
|
pub(crate) fn with_usage_worker_queue(
|
|
|
|
|
mut self,
|
|
|
|
|
queue: Option<Arc<dyn RuntimeQueueStore>>,
|
|
|
|
|
) -> Self {
|
|
|
|
|
self.usage_worker_queue = queue;
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-05 18:27:36 +08:00
|
|
|
pub(crate) fn has_database_maintenance_backend(&self) -> bool {
|
|
|
|
|
self.backends
|
|
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|backends| backends.has_database_maintenance_backend())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_database_pool_summary(&self) -> bool {
|
|
|
|
|
self.backends
|
|
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|backends| backends.has_database_pool_summary())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_wallet_daily_usage_aggregation_backend(&self) -> bool {
|
|
|
|
|
self.backends
|
|
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|backends| backends.has_wallet_daily_usage_aggregation_backend())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_stats_hourly_aggregation_backend(&self) -> bool {
|
|
|
|
|
self.backends
|
|
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|backends| backends.has_stats_hourly_aggregation_backend())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_stats_daily_aggregation_backend(&self) -> bool {
|
|
|
|
|
self.backends
|
|
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|backends| backends.has_stats_daily_aggregation_backend())
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
pub(crate) fn has_auth_api_key_reader(&self) -> bool {
|
|
|
|
|
self.auth_api_key_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_auth_api_key_writer(&self) -> bool {
|
|
|
|
|
self.auth_api_key_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_auth_module_writer(&self) -> bool {
|
|
|
|
|
self.auth_module_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_announcement_reader(&self) -> bool {
|
|
|
|
|
self.announcement_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_announcement_writer(&self) -> bool {
|
|
|
|
|
self.announcement_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-09 21:19:29 +08:00
|
|
|
pub(crate) fn has_background_task_reader(&self) -> bool {
|
|
|
|
|
self.background_task_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_background_task_writer(&self) -> bool {
|
|
|
|
|
self.background_task_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-05 18:27:36 +08:00
|
|
|
pub(crate) fn has_audit_log_reader(&self) -> bool {
|
|
|
|
|
self.backends
|
|
|
|
|
.as_ref()
|
|
|
|
|
.and_then(|backends| backends.read().audit_logs())
|
|
|
|
|
.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
pub(crate) fn has_management_token_reader(&self) -> bool {
|
|
|
|
|
self.management_token_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_management_token_writer(&self) -> bool {
|
|
|
|
|
self.management_token_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_gemini_file_mapping_reader(&self) -> bool {
|
|
|
|
|
self.gemini_file_mapping_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_gemini_file_mapping_writer(&self) -> bool {
|
|
|
|
|
self.gemini_file_mapping_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_global_model_reader(&self) -> bool {
|
|
|
|
|
self.global_model_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_global_model_writer(&self) -> bool {
|
|
|
|
|
self.global_model_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub(crate) fn has_minimal_candidate_selection_reader(&self) -> bool {
|
|
|
|
|
self.minimal_candidate_selection_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_request_candidate_reader(&self) -> bool {
|
|
|
|
|
self.request_candidate_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_request_candidate_writer(&self) -> bool {
|
|
|
|
|
self.request_candidate_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-18 11:03:49 +08:00
|
|
|
pub(crate) fn has_routing_group_reader(&self) -> bool {
|
|
|
|
|
self.routing_group_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_routing_group_writer(&self) -> bool {
|
|
|
|
|
self.routing_group_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
pub(crate) fn has_provider_catalog_reader(&self) -> bool {
|
|
|
|
|
self.provider_catalog_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_provider_catalog_writer(&self) -> bool {
|
|
|
|
|
self.provider_catalog_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-12 01:46:22 +08:00
|
|
|
pub(crate) fn has_pool_score_reader(&self) -> bool {
|
|
|
|
|
self.pool_score_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_pool_score_writer(&self) -> bool {
|
|
|
|
|
self.pool_score_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
pub(crate) fn has_proxy_node_reader(&self) -> bool {
|
|
|
|
|
self.proxy_node_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_proxy_node_writer(&self) -> bool {
|
|
|
|
|
self.proxy_node_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-12 16:02:38 +08:00
|
|
|
pub(crate) fn has_system_config_store(&self) -> bool {
|
|
|
|
|
self.system_config_values.is_some()
|
|
|
|
|
|| self
|
|
|
|
|
.backends
|
|
|
|
|
.as_ref()
|
2026-05-05 18:27:36 +08:00
|
|
|
.is_some_and(|backends| backends.has_system_config_backend())
|
2026-04-12 16:02:38 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-05 18:27:36 +08:00
|
|
|
pub(crate) fn database_driver(&self) -> Option<DatabaseDriver> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.backends
|
|
|
|
|
.as_ref()
|
2026-05-05 18:27:36 +08:00
|
|
|
.and_then(|backends| backends.database_driver())
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_provider_quota_writer(&self) -> bool {
|
|
|
|
|
self.provider_quota_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_usage_reader(&self) -> bool {
|
|
|
|
|
self.usage_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_user_reader(&self) -> bool {
|
|
|
|
|
self.user_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_usage_writer(&self) -> bool {
|
|
|
|
|
self.usage_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-08 00:18:12 +08:00
|
|
|
pub(crate) fn has_usage_worker_queue(&self) -> bool {
|
|
|
|
|
self.usage_worker_queue.is_some()
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_video_task_reader(&self) -> bool {
|
|
|
|
|
self.video_task_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_video_task_writer(&self) -> bool {
|
|
|
|
|
self.video_task_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_wallet_reader(&self) -> bool {
|
|
|
|
|
self.wallet_reader.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_wallet_writer(&self) -> bool {
|
|
|
|
|
self.wallet_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 20:23:16 +08:00
|
|
|
pub(crate) fn has_settlement_writer(&self) -> bool {
|
|
|
|
|
self.settlement_writer.is_some()
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
#[allow(dead_code)]
|
2026-04-05 20:23:16 +08:00
|
|
|
pub(crate) fn encryption_key(&self) -> Option<&str> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.config.encryption_key()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn find_system_config_value(
|
|
|
|
|
&self,
|
|
|
|
|
key: &str,
|
|
|
|
|
) -> Result<Option<serde_json::Value>, DataLayerError> {
|
|
|
|
|
if let Some(values) = &self.system_config_values {
|
|
|
|
|
return Ok(values
|
|
|
|
|
.read()
|
|
|
|
|
.expect("system config values lock")
|
|
|
|
|
.get(key)
|
|
|
|
|
.map(|entry| entry.value.clone()));
|
|
|
|
|
}
|
2026-05-05 18:27:36 +08:00
|
|
|
let Some(backends) = self.backends.as_ref() else {
|
|
|
|
|
return Ok(None);
|
|
|
|
|
};
|
|
|
|
|
backends.find_system_config_value(key).await
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn upsert_system_config_value(
|
|
|
|
|
&self,
|
|
|
|
|
key: &str,
|
|
|
|
|
value: &serde_json::Value,
|
|
|
|
|
description: Option<&str>,
|
|
|
|
|
) -> Result<serde_json::Value, DataLayerError> {
|
|
|
|
|
Ok(self
|
|
|
|
|
.upsert_system_config_entry(key, value, description)
|
|
|
|
|
.await?
|
|
|
|
|
.value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_system_config_entries(
|
|
|
|
|
&self,
|
|
|
|
|
) -> Result<Vec<StoredSystemConfigEntry>, DataLayerError> {
|
|
|
|
|
if let Some(values) = &self.system_config_values {
|
|
|
|
|
return Ok(values
|
|
|
|
|
.read()
|
|
|
|
|
.expect("system config values lock")
|
|
|
|
|
.values()
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect());
|
|
|
|
|
}
|
2026-05-05 18:27:36 +08:00
|
|
|
let Some(backends) = self.backends.as_ref() else {
|
|
|
|
|
return Ok(Vec::new());
|
|
|
|
|
};
|
|
|
|
|
backends.list_system_config_entries().await
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn upsert_system_config_entry(
|
|
|
|
|
&self,
|
|
|
|
|
key: &str,
|
|
|
|
|
value: &serde_json::Value,
|
|
|
|
|
description: Option<&str>,
|
|
|
|
|
) -> Result<StoredSystemConfigEntry, DataLayerError> {
|
|
|
|
|
if let Some(values) = &self.system_config_values {
|
|
|
|
|
let mut values = values.write().expect("system config values lock");
|
|
|
|
|
let description = description
|
|
|
|
|
.map(ToOwned::to_owned)
|
|
|
|
|
.or_else(|| values.get(key).and_then(|entry| entry.description.clone()));
|
|
|
|
|
let entry = StoredSystemConfigEntry {
|
|
|
|
|
key: key.to_string(),
|
|
|
|
|
value: value.clone(),
|
|
|
|
|
description,
|
|
|
|
|
updated_at_unix_secs: Some(current_system_config_updated_at_unix_secs()),
|
|
|
|
|
};
|
|
|
|
|
values.insert(key.to_string(), entry.clone());
|
|
|
|
|
return Ok(entry);
|
|
|
|
|
}
|
2026-05-05 18:27:36 +08:00
|
|
|
if let Some(backends) = self.backends.as_ref() {
|
|
|
|
|
if let Some(entry) = backends
|
|
|
|
|
.upsert_system_config_entry(key, value, description)
|
|
|
|
|
.await?
|
|
|
|
|
{
|
|
|
|
|
return Ok(entry);
|
2026-04-05 20:23:16 +08:00
|
|
|
}
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
2026-05-05 18:27:36 +08:00
|
|
|
Ok(StoredSystemConfigEntry {
|
|
|
|
|
key: key.to_string(),
|
|
|
|
|
value: value.clone(),
|
|
|
|
|
description: description.map(ToOwned::to_owned),
|
|
|
|
|
updated_at_unix_secs: Some(current_system_config_updated_at_unix_secs()),
|
|
|
|
|
})
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn delete_system_config_value(
|
|
|
|
|
&self,
|
|
|
|
|
key: &str,
|
|
|
|
|
) -> Result<bool, DataLayerError> {
|
|
|
|
|
if let Some(values) = &self.system_config_values {
|
|
|
|
|
return Ok(values
|
|
|
|
|
.write()
|
|
|
|
|
.expect("system config values lock")
|
|
|
|
|
.remove(key)
|
|
|
|
|
.is_some());
|
|
|
|
|
}
|
2026-05-05 18:27:36 +08:00
|
|
|
let Some(backends) = self.backends.as_ref() else {
|
|
|
|
|
return Ok(false);
|
|
|
|
|
};
|
|
|
|
|
backends.delete_system_config_value(key).await
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn read_admin_system_stats(
|
|
|
|
|
&self,
|
2026-04-05 20:23:16 +08:00
|
|
|
) -> Result<super::AdminSystemStats, DataLayerError> {
|
2026-05-05 18:27:36 +08:00
|
|
|
match self.backends.as_ref() {
|
|
|
|
|
Some(backends) => backends.read_admin_system_stats().await,
|
2026-04-05 20:23:16 +08:00
|
|
|
None => Ok(super::AdminSystemStats::default()),
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
}
|
2026-05-07 21:26:40 +08:00
|
|
|
|
|
|
|
|
pub(crate) async fn purge_admin_system_data(
|
|
|
|
|
&self,
|
|
|
|
|
target: aether_data::repository::system::AdminSystemPurgeTarget,
|
|
|
|
|
) -> Result<aether_data::repository::system::AdminSystemPurgeSummary, DataLayerError> {
|
|
|
|
|
if matches!(
|
|
|
|
|
target,
|
|
|
|
|
aether_data::repository::system::AdminSystemPurgeTarget::Config
|
|
|
|
|
) {
|
|
|
|
|
if let Some(values) = &self.system_config_values {
|
|
|
|
|
let mut values = values.write().expect("system config values lock");
|
|
|
|
|
let deleted = values.len() as u64;
|
|
|
|
|
values.clear();
|
|
|
|
|
let mut summary =
|
|
|
|
|
aether_data::repository::system::AdminSystemPurgeSummary::default();
|
|
|
|
|
summary.add("system_configs", deleted);
|
|
|
|
|
return Ok(summary);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
match self.backends.as_ref() {
|
|
|
|
|
Some(backends) => backends.purge_admin_system_data(target).await,
|
|
|
|
|
None => Ok(aether_data::repository::system::AdminSystemPurgeSummary::default()),
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-08 13:50:18 +08:00
|
|
|
|
|
|
|
|
pub(crate) async fn purge_admin_request_bodies_batch(
|
|
|
|
|
&self,
|
|
|
|
|
batch_size: usize,
|
|
|
|
|
) -> Result<aether_data::repository::system::AdminSystemPurgeSummary, DataLayerError> {
|
|
|
|
|
match self.backends.as_ref() {
|
|
|
|
|
Some(backends) => backends.purge_admin_request_bodies_batch(batch_size).await,
|
|
|
|
|
None => Ok(aether_data::repository::system::AdminSystemPurgeSummary::default()),
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|