mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
feat: add routing profile scheduling policies
This commit is contained in:
@@ -8,6 +8,7 @@ description = "Shared data contracts and repository traits for Aether Rust servi
|
||||
|
||||
[dependencies]
|
||||
aether-ai-formats.workspace = true
|
||||
aether-routing-core.workspace = true
|
||||
async-trait.workspace = true
|
||||
chrono.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
@@ -6,6 +6,7 @@ pub mod global_models;
|
||||
pub mod pool_scores;
|
||||
pub mod provider_catalog;
|
||||
pub mod quota;
|
||||
pub mod routing_profiles;
|
||||
pub mod settlement;
|
||||
pub mod usage;
|
||||
pub mod video_tasks;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
mod types;
|
||||
|
||||
pub use aether_routing_core::{RoutingGroupBindingSubject, RoutingGroupConfig, RoutingGroupRecord};
|
||||
pub use types::{
|
||||
CreateRoutingGroupBindingRecord, CreateRoutingGroupRecord, CreateRoutingGroupVersionRecord,
|
||||
RoutingGroupBindingQuery, RoutingGroupLookupKey, RoutingGroupReadRepository,
|
||||
RoutingGroupWriteRepository, StoredRoutingGroup, StoredRoutingGroupBinding,
|
||||
StoredRoutingGroupVersion, UpdateRoutingGroupBindingRecord, UpdateRoutingGroupRecord,
|
||||
};
|
||||
@@ -0,0 +1,238 @@
|
||||
use async_trait::async_trait;
|
||||
use serde_json::Value;
|
||||
|
||||
use aether_routing_core::RoutingGroupBindingSubject;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StoredRoutingGroup {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub enabled: bool,
|
||||
pub is_system_default: bool,
|
||||
pub config_json: Value,
|
||||
pub version: i64,
|
||||
pub created_at: i64,
|
||||
pub updated_at: i64,
|
||||
pub published_at: Option<i64>,
|
||||
}
|
||||
|
||||
impl StoredRoutingGroup {
|
||||
pub fn new(record: CreateRoutingGroupRecord) -> Result<Self, crate::DataLayerError> {
|
||||
validate_non_empty(&record.id, "routing_groups.id")?;
|
||||
validate_non_empty(&record.name, "routing_groups.name")?;
|
||||
validate_config_object(&record.config_json, "routing_groups.config_json")?;
|
||||
Ok(Self {
|
||||
id: record.id,
|
||||
name: record.name,
|
||||
description: record.description,
|
||||
enabled: record.enabled,
|
||||
is_system_default: record.is_system_default,
|
||||
config_json: record.config_json,
|
||||
version: record.version.max(1),
|
||||
created_at: record.created_at,
|
||||
updated_at: record.updated_at,
|
||||
published_at: record.published_at,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CreateRoutingGroupRecord {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub enabled: bool,
|
||||
pub is_system_default: bool,
|
||||
pub config_json: Value,
|
||||
pub version: i64,
|
||||
pub created_at: i64,
|
||||
pub updated_at: i64,
|
||||
pub published_at: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct UpdateRoutingGroupRecord {
|
||||
pub name: Option<String>,
|
||||
pub description: Option<Option<String>>,
|
||||
pub enabled: Option<bool>,
|
||||
pub is_system_default: Option<bool>,
|
||||
pub config_json: Option<Value>,
|
||||
pub version: Option<i64>,
|
||||
pub updated_at: i64,
|
||||
pub published_at: Option<Option<i64>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct UpdateRoutingGroupBindingRecord {
|
||||
pub group_id: Option<String>,
|
||||
pub subject_type: Option<RoutingGroupBindingSubject>,
|
||||
pub subject_id: Option<String>,
|
||||
pub is_default: Option<bool>,
|
||||
pub allow_explicit_select: Option<bool>,
|
||||
pub updated_at: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StoredRoutingGroupBinding {
|
||||
pub id: String,
|
||||
pub group_id: String,
|
||||
pub subject_type: RoutingGroupBindingSubject,
|
||||
pub subject_id: String,
|
||||
pub is_default: bool,
|
||||
pub allow_explicit_select: bool,
|
||||
pub created_at: i64,
|
||||
pub updated_at: i64,
|
||||
}
|
||||
|
||||
impl StoredRoutingGroupBinding {
|
||||
pub fn new(record: CreateRoutingGroupBindingRecord) -> Result<Self, crate::DataLayerError> {
|
||||
validate_non_empty(&record.id, "routing_group_bindings.id")?;
|
||||
validate_non_empty(&record.group_id, "routing_group_bindings.group_id")?;
|
||||
validate_non_empty(&record.subject_id, "routing_group_bindings.subject_id")?;
|
||||
Ok(Self {
|
||||
id: record.id,
|
||||
group_id: record.group_id,
|
||||
subject_type: record.subject_type,
|
||||
subject_id: record.subject_id,
|
||||
is_default: record.is_default,
|
||||
allow_explicit_select: record.allow_explicit_select,
|
||||
created_at: record.created_at,
|
||||
updated_at: record.updated_at,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CreateRoutingGroupBindingRecord {
|
||||
pub id: String,
|
||||
pub group_id: String,
|
||||
pub subject_type: RoutingGroupBindingSubject,
|
||||
pub subject_id: String,
|
||||
pub is_default: bool,
|
||||
pub allow_explicit_select: bool,
|
||||
pub created_at: i64,
|
||||
pub updated_at: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StoredRoutingGroupVersion {
|
||||
pub id: String,
|
||||
pub group_id: String,
|
||||
pub version: i64,
|
||||
pub config_json: Value,
|
||||
pub created_at: i64,
|
||||
pub created_by: Option<String>,
|
||||
}
|
||||
|
||||
impl StoredRoutingGroupVersion {
|
||||
pub fn new(record: CreateRoutingGroupVersionRecord) -> Result<Self, crate::DataLayerError> {
|
||||
validate_non_empty(&record.id, "routing_group_versions.id")?;
|
||||
validate_non_empty(&record.group_id, "routing_group_versions.group_id")?;
|
||||
validate_config_object(&record.config_json, "routing_group_versions.config_json")?;
|
||||
Ok(Self {
|
||||
id: record.id,
|
||||
group_id: record.group_id,
|
||||
version: record.version.max(1),
|
||||
config_json: record.config_json,
|
||||
created_at: record.created_at,
|
||||
created_by: record.created_by,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CreateRoutingGroupVersionRecord {
|
||||
pub id: String,
|
||||
pub group_id: String,
|
||||
pub version: i64,
|
||||
pub config_json: Value,
|
||||
pub created_at: i64,
|
||||
pub created_by: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum RoutingGroupLookupKey<'a> {
|
||||
Id(&'a str),
|
||||
Name(&'a str),
|
||||
SystemDefault,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct RoutingGroupBindingQuery {
|
||||
pub group_id: Option<String>,
|
||||
pub subject_type: Option<RoutingGroupBindingSubject>,
|
||||
pub subject_id: Option<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait RoutingGroupReadRepository: Send + Sync {
|
||||
async fn list_routing_groups(&self) -> Result<Vec<StoredRoutingGroup>, crate::DataLayerError>;
|
||||
|
||||
async fn find_routing_group(
|
||||
&self,
|
||||
lookup: RoutingGroupLookupKey<'_>,
|
||||
) -> Result<Option<StoredRoutingGroup>, crate::DataLayerError>;
|
||||
|
||||
async fn list_routing_group_bindings(
|
||||
&self,
|
||||
query: &RoutingGroupBindingQuery,
|
||||
) -> Result<Vec<StoredRoutingGroupBinding>, crate::DataLayerError>;
|
||||
|
||||
async fn list_routing_group_versions(
|
||||
&self,
|
||||
group_id: &str,
|
||||
) -> Result<Vec<StoredRoutingGroupVersion>, crate::DataLayerError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait RoutingGroupWriteRepository: Send + Sync {
|
||||
async fn create_routing_group(
|
||||
&self,
|
||||
record: CreateRoutingGroupRecord,
|
||||
) -> Result<StoredRoutingGroup, crate::DataLayerError>;
|
||||
|
||||
async fn update_routing_group(
|
||||
&self,
|
||||
id: &str,
|
||||
patch: UpdateRoutingGroupRecord,
|
||||
) -> Result<Option<StoredRoutingGroup>, crate::DataLayerError>;
|
||||
|
||||
async fn delete_routing_group(&self, id: &str) -> Result<bool, crate::DataLayerError>;
|
||||
|
||||
async fn create_routing_group_binding(
|
||||
&self,
|
||||
record: CreateRoutingGroupBindingRecord,
|
||||
) -> Result<StoredRoutingGroupBinding, crate::DataLayerError>;
|
||||
|
||||
async fn delete_routing_group_binding(&self, id: &str) -> Result<bool, crate::DataLayerError>;
|
||||
|
||||
async fn update_routing_group_binding(
|
||||
&self,
|
||||
id: &str,
|
||||
patch: UpdateRoutingGroupBindingRecord,
|
||||
) -> Result<Option<StoredRoutingGroupBinding>, crate::DataLayerError>;
|
||||
|
||||
async fn create_routing_group_version(
|
||||
&self,
|
||||
record: CreateRoutingGroupVersionRecord,
|
||||
) -> Result<StoredRoutingGroupVersion, crate::DataLayerError>;
|
||||
}
|
||||
|
||||
fn validate_non_empty(value: &str, field: &str) -> Result<(), crate::DataLayerError> {
|
||||
if value.trim().is_empty() {
|
||||
return Err(crate::DataLayerError::InvalidInput(format!(
|
||||
"{field} is empty"
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_config_object(value: &Value, field: &str) -> Result<(), crate::DataLayerError> {
|
||||
if !value.is_object() {
|
||||
return Err(crate::DataLayerError::InvalidInput(format!(
|
||||
"{field} must be a JSON object"
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user