use cache::AppCache; use config::AppConfig; use db::AppDatabase; use deadpool_redis::cluster::Pool as RedisPool; use email::AppEmail; use error::AppError; use serde::Deserialize; use session::Session; use storage::AppStorage; use tonic::transport::Channel; use uuid::Uuid; pub mod agent; pub mod ai; pub mod auth; pub mod error; pub mod git; pub mod issues; pub mod metrics; pub mod pull_request; pub mod user; pub mod users; pub mod workspace; pub fn session_user(ctx: &Session) -> Result { ctx.user().ok_or(AppError::Unauthorized) } pub fn non_empty(value: String) -> Option { if value.is_empty() { None } else { Some(value) } } pub fn constant_time_eq(a: &str, b: &str) -> bool { if a.len() != b.len() { return false; } a.bytes() .zip(b.bytes()) .fold(0u8, |acc, (x, y)| acc | (x ^ y)) == 0 } #[derive(Debug, Clone, Deserialize, utoipa::IntoParams, utoipa::ToSchema)] pub struct Pagination { pub offset: Option, pub limit: Option, } impl Pagination { pub fn offset(&self) -> u32 { self.offset.unwrap_or(0) } pub fn limit(&self) -> u32 { self.limit.unwrap_or(20).min(100) } } #[derive(Clone)] pub struct AppService { pub db: AppDatabase, pub cache: AppCache, pub email: AppEmail, pub storage: AppStorage, pub config: AppConfig, pub git: Channel, pub redis_pool: RedisPool, pub metrics_registry: track::MetricsRegistry, pub metrics: metrics::ServiceMetrics, }