2026-04-04 01:40:24 +08:00
|
|
|
use super::{AppState, GatewayError, LocalMutationOutcome, LocalProviderDeleteTaskState};
|
2026-04-20 22:59:02 +08:00
|
|
|
use crate::handlers::shared::sync_provider_key_oauth_status_snapshot;
|
2026-04-07 02:50:19 +08:00
|
|
|
use aether_data_contracts::repository::{candidates, global_models, provider_catalog};
|
2026-04-20 22:59:02 +08:00
|
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
2026-03-31 19:19:04 +08:00
|
|
|
|
|
|
|
|
impl AppState {
|
|
|
|
|
pub fn has_provider_catalog_data_reader(&self) -> bool {
|
|
|
|
|
self.data.has_provider_catalog_reader()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_provider_catalog_data_writer(&self) -> bool {
|
|
|
|
|
self.data.has_provider_catalog_writer()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_global_model_data_reader(&self) -> bool {
|
|
|
|
|
self.data.has_global_model_reader()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_global_model_data_writer(&self) -> bool {
|
|
|
|
|
self.data.has_global_model_writer()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_minimal_candidate_selection_reader(&self) -> bool {
|
|
|
|
|
self.data.has_minimal_candidate_selection_reader()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_management_token_reader(&self) -> bool {
|
|
|
|
|
self.data.has_management_token_reader()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn has_management_token_writer(&self) -> bool {
|
|
|
|
|
self.data.has_management_token_writer()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_provider_catalog_providers(
|
|
|
|
|
&self,
|
|
|
|
|
active_only: bool,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<provider_catalog::StoredProviderCatalogProvider>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_providers(active_only)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_provider_catalog_endpoints_by_provider_ids(
|
|
|
|
|
&self,
|
|
|
|
|
provider_ids: &[String],
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<provider_catalog::StoredProviderCatalogEndpoint>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_endpoints_by_provider_ids(provider_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_public_global_models(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
query: &global_models::PublicGlobalModelQuery,
|
|
|
|
|
) -> Result<global_models::StoredPublicGlobalModelPage, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_public_global_models(query)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_management_tokens(
|
|
|
|
|
&self,
|
|
|
|
|
query: &aether_data::repository::management_tokens::ManagementTokenListQuery,
|
|
|
|
|
) -> Result<
|
|
|
|
|
aether_data::repository::management_tokens::StoredManagementTokenListPage,
|
|
|
|
|
GatewayError,
|
|
|
|
|
> {
|
|
|
|
|
self.data
|
|
|
|
|
.list_management_tokens(query)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn get_management_token_with_user(
|
|
|
|
|
&self,
|
|
|
|
|
token_id: &str,
|
|
|
|
|
) -> Result<
|
|
|
|
|
Option<aether_data::repository::management_tokens::StoredManagementTokenWithUser>,
|
|
|
|
|
GatewayError,
|
|
|
|
|
> {
|
|
|
|
|
self.data
|
|
|
|
|
.get_management_token_with_user(token_id)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-12 16:02:38 +08:00
|
|
|
pub(crate) async fn get_management_token_with_user_by_hash(
|
|
|
|
|
&self,
|
|
|
|
|
token_hash: &str,
|
|
|
|
|
) -> Result<
|
|
|
|
|
Option<aether_data::repository::management_tokens::StoredManagementTokenWithUser>,
|
|
|
|
|
GatewayError,
|
|
|
|
|
> {
|
|
|
|
|
self.data
|
|
|
|
|
.get_management_token_with_user_by_hash(token_hash)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
pub(crate) async fn create_management_token(
|
|
|
|
|
&self,
|
|
|
|
|
record: &aether_data::repository::management_tokens::CreateManagementTokenRecord,
|
|
|
|
|
) -> Result<
|
|
|
|
|
LocalMutationOutcome<aether_data::repository::management_tokens::StoredManagementToken>,
|
|
|
|
|
GatewayError,
|
|
|
|
|
> {
|
|
|
|
|
self.data
|
|
|
|
|
.create_management_token(record)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn update_management_token(
|
|
|
|
|
&self,
|
|
|
|
|
record: &aether_data::repository::management_tokens::UpdateManagementTokenRecord,
|
|
|
|
|
) -> Result<
|
|
|
|
|
LocalMutationOutcome<aether_data::repository::management_tokens::StoredManagementToken>,
|
|
|
|
|
GatewayError,
|
|
|
|
|
> {
|
|
|
|
|
self.data
|
|
|
|
|
.update_management_token(record)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn delete_management_token(
|
|
|
|
|
&self,
|
|
|
|
|
token_id: &str,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
|
|
|
|
self.data
|
|
|
|
|
.delete_management_token(token_id)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-12 16:02:38 +08:00
|
|
|
pub(crate) async fn record_management_token_usage(
|
|
|
|
|
&self,
|
|
|
|
|
token_id: &str,
|
|
|
|
|
last_used_ip: Option<&str>,
|
|
|
|
|
) -> Result<
|
|
|
|
|
Option<aether_data::repository::management_tokens::StoredManagementToken>,
|
|
|
|
|
GatewayError,
|
|
|
|
|
> {
|
|
|
|
|
self.data
|
|
|
|
|
.record_management_token_usage(token_id, last_used_ip)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
pub(crate) async fn set_management_token_active(
|
|
|
|
|
&self,
|
|
|
|
|
token_id: &str,
|
|
|
|
|
is_active: bool,
|
|
|
|
|
) -> Result<
|
|
|
|
|
Option<aether_data::repository::management_tokens::StoredManagementToken>,
|
|
|
|
|
GatewayError,
|
|
|
|
|
> {
|
|
|
|
|
self.data
|
|
|
|
|
.set_management_token_active(token_id, is_active)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn regenerate_management_token_secret(
|
|
|
|
|
&self,
|
|
|
|
|
mutation: &aether_data::repository::management_tokens::RegenerateManagementTokenSecret,
|
|
|
|
|
) -> Result<
|
|
|
|
|
LocalMutationOutcome<aether_data::repository::management_tokens::StoredManagementToken>,
|
|
|
|
|
GatewayError,
|
|
|
|
|
> {
|
|
|
|
|
self.data
|
|
|
|
|
.regenerate_management_token_secret(mutation)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn get_public_global_model_by_name(
|
|
|
|
|
&self,
|
|
|
|
|
model_name: &str,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Option<global_models::StoredPublicGlobalModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.get_public_global_model_by_name(model_name)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_public_catalog_models(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
query: &global_models::PublicCatalogModelListQuery,
|
|
|
|
|
) -> Result<Vec<global_models::StoredPublicCatalogModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_public_catalog_models(query)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn search_public_catalog_models(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
query: &global_models::PublicCatalogModelSearchQuery,
|
|
|
|
|
) -> Result<Vec<global_models::StoredPublicCatalogModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.search_public_catalog_models(query)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_admin_provider_models(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
query: &global_models::AdminProviderModelListQuery,
|
|
|
|
|
) -> Result<Vec<global_models::StoredAdminProviderModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_admin_provider_models(query)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_admin_global_models(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
query: &global_models::AdminGlobalModelListQuery,
|
|
|
|
|
) -> Result<global_models::StoredAdminGlobalModelPage, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_admin_global_models(query)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn get_admin_provider_model(
|
|
|
|
|
&self,
|
|
|
|
|
provider_id: &str,
|
|
|
|
|
model_id: &str,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Option<global_models::StoredAdminProviderModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.get_admin_provider_model(provider_id, model_id)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_admin_provider_available_source_models(
|
|
|
|
|
&self,
|
|
|
|
|
provider_id: &str,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<global_models::StoredAdminProviderModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_admin_provider_available_source_models(provider_id)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn get_admin_global_model_by_id(
|
|
|
|
|
&self,
|
|
|
|
|
global_model_id: &str,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Option<global_models::StoredAdminGlobalModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.get_admin_global_model_by_id(global_model_id)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn get_admin_global_model_by_name(
|
|
|
|
|
&self,
|
|
|
|
|
model_name: &str,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Option<global_models::StoredAdminGlobalModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.get_admin_global_model_by_name(model_name)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_admin_provider_models_by_global_model_id(
|
|
|
|
|
&self,
|
|
|
|
|
global_model_id: &str,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<global_models::StoredAdminProviderModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_admin_provider_models_by_global_model_id(global_model_id)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn create_admin_provider_model(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
record: &global_models::UpsertAdminProviderModelRecord,
|
|
|
|
|
) -> Result<Option<global_models::StoredAdminProviderModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.create_admin_provider_model(record)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn update_admin_provider_model(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
record: &global_models::UpsertAdminProviderModelRecord,
|
|
|
|
|
) -> Result<Option<global_models::StoredAdminProviderModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.update_admin_provider_model(record)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn delete_admin_provider_model(
|
|
|
|
|
&self,
|
|
|
|
|
provider_id: &str,
|
|
|
|
|
model_id: &str,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
|
|
|
|
self.data
|
|
|
|
|
.delete_admin_provider_model(provider_id, model_id)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn create_admin_global_model(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
record: &global_models::CreateAdminGlobalModelRecord,
|
|
|
|
|
) -> Result<Option<global_models::StoredAdminGlobalModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.create_admin_global_model(record)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn update_admin_global_model(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
record: &global_models::UpdateAdminGlobalModelRecord,
|
|
|
|
|
) -> Result<Option<global_models::StoredAdminGlobalModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.update_admin_global_model(record)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn delete_admin_global_model(
|
|
|
|
|
&self,
|
|
|
|
|
global_model_id: &str,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
|
|
|
|
self.data
|
|
|
|
|
.delete_admin_global_model(global_model_id)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_provider_model_stats(
|
|
|
|
|
&self,
|
|
|
|
|
provider_ids: &[String],
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<global_models::StoredProviderModelStats>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_model_stats(provider_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_active_global_model_ids_by_provider_ids(
|
|
|
|
|
&self,
|
|
|
|
|
provider_ids: &[String],
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<global_models::StoredProviderActiveGlobalModel>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_active_global_model_ids_by_provider_ids(provider_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_finalized_request_candidates_by_endpoint_ids_since(
|
|
|
|
|
&self,
|
|
|
|
|
endpoint_ids: &[String],
|
|
|
|
|
since_unix_secs: u64,
|
|
|
|
|
limit: usize,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<candidates::StoredRequestCandidate>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_finalized_request_candidates_by_endpoint_ids_since(
|
|
|
|
|
endpoint_ids,
|
|
|
|
|
since_unix_secs,
|
|
|
|
|
limit,
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn count_finalized_request_candidate_statuses_by_endpoint_ids_since(
|
|
|
|
|
&self,
|
|
|
|
|
endpoint_ids: &[String],
|
|
|
|
|
since_unix_secs: u64,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<candidates::PublicHealthStatusCount>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.count_finalized_request_candidate_statuses_by_endpoint_ids_since(
|
|
|
|
|
endpoint_ids,
|
|
|
|
|
since_unix_secs,
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn aggregate_finalized_request_candidate_timeline_by_endpoint_ids_since(
|
|
|
|
|
&self,
|
|
|
|
|
endpoint_ids: &[String],
|
|
|
|
|
since_unix_secs: u64,
|
|
|
|
|
until_unix_secs: u64,
|
|
|
|
|
segments: u32,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<candidates::PublicHealthTimelineBucket>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.aggregate_finalized_request_candidate_timeline_by_endpoint_ids_since(
|
|
|
|
|
endpoint_ids,
|
|
|
|
|
since_unix_secs,
|
|
|
|
|
until_unix_secs,
|
|
|
|
|
segments,
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_provider_catalog_keys_by_provider_ids(
|
|
|
|
|
&self,
|
|
|
|
|
provider_ids: &[String],
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<provider_catalog::StoredProviderCatalogKey>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_keys_by_provider_ids(provider_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-12 20:45:47 +08:00
|
|
|
pub(crate) async fn list_provider_catalog_key_summaries_by_provider_ids(
|
|
|
|
|
&self,
|
|
|
|
|
provider_ids: &[String],
|
|
|
|
|
) -> Result<Vec<provider_catalog::StoredProviderCatalogKey>, GatewayError> {
|
|
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_key_summaries_by_provider_ids(provider_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
pub(crate) async fn list_provider_catalog_keys_by_ids(
|
|
|
|
|
&self,
|
|
|
|
|
key_ids: &[String],
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<provider_catalog::StoredProviderCatalogKey>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_keys_by_ids(key_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_provider_catalog_key_page(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
query: &provider_catalog::ProviderCatalogKeyListQuery,
|
|
|
|
|
) -> Result<provider_catalog::StoredProviderCatalogKeyPage, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_key_page(query)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn list_provider_catalog_key_stats_by_provider_ids(
|
|
|
|
|
&self,
|
|
|
|
|
provider_ids: &[String],
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<provider_catalog::StoredProviderCatalogKeyStats>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_key_stats_by_provider_ids(provider_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn create_provider_catalog_key(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
key: &provider_catalog::StoredProviderCatalogKey,
|
|
|
|
|
) -> Result<Option<provider_catalog::StoredProviderCatalogKey>, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let created = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.create_provider_catalog_key(key)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if created.is_some() {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(created)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn create_provider_catalog_provider(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
provider: &provider_catalog::StoredProviderCatalogProvider,
|
2026-03-31 19:19:04 +08:00
|
|
|
shift_existing_priorities_from: Option<i32>,
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Option<provider_catalog::StoredProviderCatalogProvider>, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let created = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.create_provider_catalog_provider(provider, shift_existing_priorities_from)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if created.is_some() {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(created)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn update_provider_catalog_provider(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
provider: &provider_catalog::StoredProviderCatalogProvider,
|
|
|
|
|
) -> Result<Option<provider_catalog::StoredProviderCatalogProvider>, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let updated = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.update_provider_catalog_provider(provider)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if updated.is_some() {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(updated)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn delete_provider_catalog_provider(
|
|
|
|
|
&self,
|
|
|
|
|
provider_id: &str,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let deleted = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.delete_provider_catalog_provider(provider_id)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if deleted {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(deleted)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn cleanup_deleted_provider_catalog_refs(
|
|
|
|
|
&self,
|
|
|
|
|
provider_id: &str,
|
|
|
|
|
endpoint_ids: &[String],
|
|
|
|
|
key_ids: &[String],
|
|
|
|
|
) -> Result<(), GatewayError> {
|
|
|
|
|
self.data
|
|
|
|
|
.cleanup_deleted_provider_catalog_refs(provider_id, endpoint_ids, key_ids)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if !endpoint_ids.is_empty() || !key_ids.is_empty() {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn create_provider_catalog_endpoint(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
endpoint: &provider_catalog::StoredProviderCatalogEndpoint,
|
|
|
|
|
) -> Result<Option<provider_catalog::StoredProviderCatalogEndpoint>, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let created = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.create_provider_catalog_endpoint(endpoint)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if created.is_some() {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(created)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn update_provider_catalog_endpoint(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
endpoint: &provider_catalog::StoredProviderCatalogEndpoint,
|
|
|
|
|
) -> Result<Option<provider_catalog::StoredProviderCatalogEndpoint>, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let updated = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.update_provider_catalog_endpoint(endpoint)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if updated.is_some() {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(updated)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn delete_provider_catalog_endpoint(
|
|
|
|
|
&self,
|
|
|
|
|
endpoint_id: &str,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let deleted = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.delete_provider_catalog_endpoint(endpoint_id)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if deleted {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(deleted)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn update_provider_catalog_key(
|
|
|
|
|
&self,
|
2026-04-07 02:50:19 +08:00
|
|
|
key: &provider_catalog::StoredProviderCatalogKey,
|
|
|
|
|
) -> Result<Option<provider_catalog::StoredProviderCatalogKey>, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let updated = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.update_provider_catalog_key(key)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if updated.is_some() {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(updated)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-14 14:51:26 +08:00
|
|
|
pub(crate) async fn update_provider_catalog_key_upstream_metadata(
|
|
|
|
|
&self,
|
|
|
|
|
key_id: &str,
|
|
|
|
|
upstream_metadata: Option<&serde_json::Value>,
|
|
|
|
|
updated_at_unix_secs: Option<u64>,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
|
|
|
|
let updated = self
|
|
|
|
|
.data
|
|
|
|
|
.update_provider_catalog_key_upstream_metadata(
|
|
|
|
|
key_id,
|
|
|
|
|
upstream_metadata,
|
|
|
|
|
updated_at_unix_secs,
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if updated {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(updated)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
pub(crate) async fn delete_provider_catalog_key(
|
|
|
|
|
&self,
|
|
|
|
|
key_id: &str,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let deleted = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.delete_provider_catalog_key(key_id)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if deleted {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(deleted)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn clear_provider_catalog_key_oauth_invalid_marker(
|
|
|
|
|
&self,
|
|
|
|
|
key_id: &str,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
2026-04-20 22:59:02 +08:00
|
|
|
let Some(mut key) = self
|
|
|
|
|
.data
|
|
|
|
|
.list_provider_catalog_keys_by_ids(&[key_id.to_string()])
|
2026-03-31 19:19:04 +08:00
|
|
|
.await
|
2026-04-20 22:59:02 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?
|
|
|
|
|
.into_iter()
|
|
|
|
|
.next()
|
|
|
|
|
else {
|
|
|
|
|
return Ok(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
key.oauth_invalid_at_unix_secs = None;
|
|
|
|
|
key.oauth_invalid_reason = None;
|
|
|
|
|
key.status_snapshot =
|
|
|
|
|
sync_provider_key_oauth_status_snapshot(key.status_snapshot.as_ref(), &key);
|
|
|
|
|
key.updated_at_unix_secs = SystemTime::now()
|
|
|
|
|
.duration_since(UNIX_EPOCH)
|
|
|
|
|
.ok()
|
|
|
|
|
.map(|duration| duration.as_secs());
|
|
|
|
|
|
|
|
|
|
self.update_provider_catalog_key(&key)
|
|
|
|
|
.await
|
|
|
|
|
.map(|updated| updated.is_some())
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn put_provider_delete_task(&self, task: LocalProviderDeleteTaskState) {
|
|
|
|
|
let mut tasks = self
|
|
|
|
|
.provider_delete_tasks
|
|
|
|
|
.lock()
|
|
|
|
|
.expect("provider delete tasks cache should lock");
|
|
|
|
|
tasks.insert(task.task_id.clone(), task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn get_provider_delete_task(
|
|
|
|
|
&self,
|
|
|
|
|
task_id: &str,
|
|
|
|
|
) -> Option<LocalProviderDeleteTaskState> {
|
|
|
|
|
let tasks = self
|
|
|
|
|
.provider_delete_tasks
|
|
|
|
|
.lock()
|
|
|
|
|
.expect("provider delete tasks cache should lock");
|
|
|
|
|
tasks.get(task_id).cloned()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn read_provider_catalog_providers_by_ids(
|
|
|
|
|
&self,
|
|
|
|
|
provider_ids: &[String],
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<provider_catalog::StoredProviderCatalogProvider>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_providers_by_ids(provider_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn read_provider_catalog_endpoints_by_ids(
|
|
|
|
|
&self,
|
|
|
|
|
endpoint_ids: &[String],
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<provider_catalog::StoredProviderCatalogEndpoint>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_endpoints_by_ids(endpoint_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) async fn read_provider_catalog_keys_by_ids(
|
|
|
|
|
&self,
|
|
|
|
|
key_ids: &[String],
|
2026-04-07 02:50:19 +08:00
|
|
|
) -> Result<Vec<provider_catalog::StoredProviderCatalogKey>, GatewayError> {
|
2026-03-31 19:19:04 +08:00
|
|
|
self.data
|
|
|
|
|
.list_provider_catalog_keys_by_ids(key_ids)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-18 11:35:11 +08:00
|
|
|
pub(crate) async fn update_provider_catalog_key_format_health(
|
|
|
|
|
&self,
|
|
|
|
|
key_id: &str,
|
|
|
|
|
api_format: &str,
|
|
|
|
|
health_by_format: &serde_json::Value,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
|
|
|
|
let api_format = api_format.trim();
|
|
|
|
|
if api_format.is_empty() {
|
|
|
|
|
return Ok(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let Some(current_key) = self
|
|
|
|
|
.read_provider_catalog_keys_by_ids(&[key_id.to_string()])
|
|
|
|
|
.await?
|
|
|
|
|
.into_iter()
|
|
|
|
|
.next()
|
|
|
|
|
else {
|
|
|
|
|
return Ok(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if current_key.health_by_format.as_ref() == Some(health_by_format) {
|
|
|
|
|
return Ok(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.update_provider_catalog_key_health_state(
|
|
|
|
|
key_id,
|
|
|
|
|
current_key.is_active,
|
|
|
|
|
Some(health_by_format),
|
|
|
|
|
current_key.circuit_breaker_by_format.as_ref(),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 19:19:04 +08:00
|
|
|
pub(crate) async fn update_provider_catalog_key_health_state(
|
|
|
|
|
&self,
|
|
|
|
|
key_id: &str,
|
|
|
|
|
is_active: bool,
|
|
|
|
|
health_by_format: Option<&serde_json::Value>,
|
|
|
|
|
circuit_breaker_by_format: Option<&serde_json::Value>,
|
|
|
|
|
) -> Result<bool, GatewayError> {
|
2026-04-03 14:59:58 +08:00
|
|
|
let updated = self
|
|
|
|
|
.data
|
2026-03-31 19:19:04 +08:00
|
|
|
.update_provider_catalog_key_health_state(
|
|
|
|
|
key_id,
|
|
|
|
|
is_active,
|
|
|
|
|
health_by_format,
|
|
|
|
|
circuit_breaker_by_format,
|
|
|
|
|
)
|
|
|
|
|
.await
|
2026-04-03 14:59:58 +08:00
|
|
|
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
|
|
|
|
if updated {
|
|
|
|
|
self.clear_provider_transport_snapshot_cache();
|
|
|
|
|
}
|
|
|
|
|
Ok(updated)
|
2026-03-31 19:19:04 +08:00
|
|
|
}
|
|
|
|
|
}
|