Files
zhenyi 420dedbc1e feat(service): expand service layer with new domain operations
- Add IM service modules: audit, channel roles, custom emojis, forum
  tags, integrations, invitations, repo links, slash commands, stages,
  voice, webhooks
- Add PR service modules: review requests, templates
- Add repo service modules: contributors, release assets, git extras
  (archive, branch rename, commit extras, diff/merge, tag, tree)
- Add user service: social (follow/block)
- Add internal auth service
- Update existing service modules with expanded functionality
- Remove deleted IM modules: articles, delivery trace, drafts,
  follows, messages, polls, presence, reactions, threads
2026-06-10 18:49:32 +08:00

66 lines
2.0 KiB
Rust

use std::sync::Arc;
use uuid::Uuid;
use crate::cache::AppCache;
use crate::cache::redis::AppRedis;
use crate::config::AppConfig;
use crate::error::AppError;
use crate::etcd::EtcdRegistry;
use crate::models::db::AppDatabase;
use crate::queue::NatsQueue;
use crate::service::im::events::ImEventBus;
use crate::service::util::set_local_user_id;
use crate::storage::s3::AppS3Storage;
/// Shared infrastructure context for all domain services.
///
/// Each sub-service (Auth, User, Workspace, Repo) holds an `Arc<ServiceContext>`
/// so they share the same database, cache, and other infrastructure without
/// duplicating ownership.
#[derive(Clone)]
pub struct ServiceContext {
pub version: String,
pub db: AppDatabase,
pub redis: AppRedis,
pub cache: Arc<AppCache>,
pub config: AppConfig,
pub storage: AppS3Storage,
/// etcd-based service registry for discovering git and mail RPC services.
pub registry: Arc<EtcdRegistry>,
/// NATS JetStream queue for real-time event broadcasting.
pub nats: Arc<NatsQueue>,
pub im_events: Arc<ImEventBus>,
}
impl ServiceContext {
/// Run a block of work inside a database transaction.
///
/// - Begins a transaction on the writer pool
/// - Sets `app.current_user_id` for RLS / audit triggers
/// - Commits on success, rolls back on error
pub async fn run_in_transaction<F, Fut, T>(&self, user_uid: Uuid, f: F) -> Result<T, AppError>
where
F: FnOnce(&mut sqlx::Transaction<'_, sqlx::Postgres>) -> Fut,
Fut: std::future::Future<Output = Result<T, AppError>>,
{
let mut txn = self
.db
.writer()
.begin()
.await
.map_err(|_| AppError::TxnError)?;
sqlx::query(set_local_user_id(user_uid))
.execute(&mut *txn)
.await
.map_err(AppError::Database)?;
let result = f(&mut txn).await?;
txn.commit().await.map_err(|_| AppError::TxnError)?;
Ok(result)
}
}