lab_resource_manager/interface/slack/
app.rs

1//! Slackアプリケーションコア
2//!
3//! 依存関係を管理し、Slackインタラクションのメインエントリポイントを提供
4
5use crate::application::usecases::create_resource_usage::CreateResourceUsageUseCase;
6use crate::application::usecases::delete_resource_usage::DeleteResourceUsageUseCase;
7use crate::application::usecases::grant_user_resource_access::GrantUserResourceAccessUseCase;
8use crate::application::usecases::update_resource_usage::UpdateResourceUsageUseCase;
9use crate::domain::ports::repositories::{IdentityLinkRepository, ResourceUsageRepository};
10use crate::infrastructure::config::ResourceConfig;
11use slack_morphism::prelude::*;
12use std::collections::HashMap;
13use std::sync::{Arc, RwLock};
14use tokio_util::task::TaskTracker;
15
16/// 依存性注入を備えたSlackアプリケーション
17///
18/// Slackインタラクションに必要なすべての依存関係を保持します。
19pub struct SlackApp<R: ResourceUsageRepository> {
20    // UseCases
21    pub grant_access_usecase: Arc<GrantUserResourceAccessUseCase>,
22    pub create_resource_usage_usecase: Arc<CreateResourceUsageUseCase<R>>,
23    pub update_resource_usage_usecase: Arc<UpdateResourceUsageUseCase<R>>,
24    pub delete_usage_usecase: Arc<DeleteResourceUsageUseCase<R>>,
25
26    // リポジトリ
27    pub identity_repo: Arc<dyn IdentityLinkRepository>,
28
29    // 設定
30    pub resource_config: Arc<ResourceConfig>,
31
32    // Slackインフラストラクチャ
33    pub slack_client: Arc<SlackHyperClient>,
34    pub bot_token: SlackApiToken,
35
36    // セッション状態(user_id -> channel_id のマッピング)
37    pub user_channel_map: Arc<RwLock<HashMap<SlackUserId, SlackChannelId>>>,
38
39    // ランタイム
40    pub task_tracker: TaskTracker,
41    pub http_client: reqwest::Client,
42}
43
44impl<R: ResourceUsageRepository + Send + Sync + 'static> SlackApp<R> {
45    /// 新しいSlackAppを作成
46    ///
47    /// # 引数
48    /// * `grant_access_usecase` - ユーザーアクセス権限付与UseCase
49    /// * `create_resource_usage_usecase` - リソース使用予定作成UseCase
50    /// * `update_resource_usage_usecase` - リソース使用予定更新UseCase
51    /// * `delete_usage_usecase` - リソース使用予定削除UseCase
52    /// * `identity_repo` - ID紐付けリポジトリ
53    /// * `resource_config` - リソース設定
54    /// * `slack_client` - Slackクライアント
55    /// * `bot_token` - Bot Token
56    #[allow(clippy::too_many_arguments)]
57    pub fn new(
58        grant_access_usecase: Arc<GrantUserResourceAccessUseCase>,
59        create_resource_usage_usecase: Arc<CreateResourceUsageUseCase<R>>,
60        update_resource_usage_usecase: Arc<UpdateResourceUsageUseCase<R>>,
61        delete_usage_usecase: Arc<DeleteResourceUsageUseCase<R>>,
62        identity_repo: Arc<dyn IdentityLinkRepository>,
63        resource_config: Arc<ResourceConfig>,
64        slack_client: Arc<SlackHyperClient>,
65        bot_token: SlackApiToken,
66    ) -> Self {
67        Self {
68            grant_access_usecase,
69            create_resource_usage_usecase,
70            update_resource_usage_usecase,
71            delete_usage_usecase,
72            identity_repo,
73            resource_config,
74            slack_client,
75            bot_token,
76            user_channel_map: Arc::new(RwLock::new(HashMap::new())),
77            task_tracker: TaskTracker::new(),
78            http_client: reqwest::Client::new(),
79        }
80    }
81
82    /// すべてのバックグラウンドタスクの完了を待機
83    ///
84    /// シャットダウン時に呼び出して、グレースフルな終了を保証します
85    pub async fn shutdown(&self) {
86        self.task_tracker.close();
87        self.task_tracker.wait().await;
88    }
89}