Skip to main content

platform/config/
ais.rs

1//! AIS (Actor Identity Service) 配置
2
3use crate::config::signer::SignerClientConfig;
4use serde::{Deserialize, Serialize};
5
6/// AIS 服务配置
7///
8/// Service enable/disable is controlled by the bitmask in ActrixConfig.enable.
9/// The ENABLE_AIS bit (bit 3) must be set to enable this service.
10#[derive(Debug, Serialize, Deserialize, Clone, Default)]
11pub struct AisConfig {
12    /// AIS 服务器配置
13    #[serde(default)]
14    pub server: AisServerConfig,
15
16    /// AIS 的依赖服务配置
17    #[serde(default)]
18    pub dependencies: AisDependencies,
19}
20
21/// AIS 服务器配置
22#[derive(Debug, Serialize, Deserialize, Clone)]
23pub struct AisServerConfig {
24    /// Signaling Server 心跳间隔(秒)
25    ///
26    /// 在 RegisterResponse 中返回,指导客户端连接 Signaling Server 后的心跳频率
27    #[serde(default = "default_signaling_heartbeat_interval_secs")]
28    pub signaling_heartbeat_interval_secs: u32,
29
30    /// Token 有效期(秒)
31    ///
32    /// 生成的 AIdCredential 的过期时间
33    #[serde(default = "default_token_ttl_secs")]
34    pub token_ttl_secs: u64,
35
36    /// Renewal token 有效期(秒)
37    ///
38    /// 初始签发 renewal token 时的 TTL。到达 rotation window 时
39    /// 确定性派生 successor token,旧 token 在自身 expiry 前持续有效。
40    #[serde(default = "default_renewal_token_ttl_secs")]
41    pub renewal_token_ttl_secs: u64,
42
43    /// Renewal rotation window(秒)
44    ///
45    /// 当 renewal token 剩余有效期小于此值时进入 rotation window,
46    /// 开始确定性派生 successor token。
47    #[serde(default = "default_renewal_rotation_window_secs")]
48    pub renewal_rotation_window_secs: u64,
49
50    /// Renewal token secret(base64 编码,解码后至少 32 字节)
51    ///
52    /// 用于确定性派生 successor token(HMAC-SHA256)。
53    /// 必须在同一 actrix 集群内一致。不得使用 `actrix_shared_key` 作为回退。
54    #[serde(default)]
55    pub renewal_token_secret: String,
56}
57
58/// AIS 依赖的外部服务
59#[derive(Debug, Serialize, Deserialize, Clone, Default)]
60pub struct AisDependencies {
61    /// Signer 客户端配置
62    ///
63    /// 如果未配置,AIS 会自动查找本地 Signer 服务:
64    /// - 如果 Signer 服务已启用(ENABLE_SIGNER 位已设置),使用 localhost:SIGNER_PORT
65    /// - 否则返回配置错误
66    #[serde(default)]
67    pub signer: Option<SignerClientConfig>,
68}
69
70impl Default for AisServerConfig {
71    fn default() -> Self {
72        Self {
73            signaling_heartbeat_interval_secs: default_signaling_heartbeat_interval_secs(),
74            token_ttl_secs: default_token_ttl_secs(),
75            renewal_token_ttl_secs: default_renewal_token_ttl_secs(),
76            renewal_rotation_window_secs: default_renewal_rotation_window_secs(),
77            renewal_token_secret: String::new(),
78        }
79    }
80}
81
82/// 默认 Signaling Server 心跳间隔:30 秒
83fn default_signaling_heartbeat_interval_secs() -> u32 {
84    30
85}
86
87/// 默认 Token 有效期:1 小时(3600 秒)
88fn default_token_ttl_secs() -> u64 {
89    3600
90}
91
92/// 默认 Renewal Token 有效期:24 小时(86400 秒)
93fn default_renewal_token_ttl_secs() -> u64 {
94    86400
95}
96
97/// 默认 Renewal Rotation Window:6 小时(21600 秒)
98fn default_renewal_rotation_window_secs() -> u64 {
99    21600
100}
101
102impl AisConfig {
103    /// 获取 Signer 客户端配置
104    ///
105    /// 支持智能默认:
106    /// 1. 如果显式配置了 dependencies.signer,直接返回
107    /// 2. 如果本地启用了 Signer 服务,返回指向本地 KS 的配置
108    /// 3. 否则返回 None
109    pub fn get_signer_client_config(
110        &self,
111        global_config: &super::ActrixConfig,
112    ) -> Option<SignerClientConfig> {
113        // 优先使用显式配置
114        if let Some(ref signer_config) = self.dependencies.signer {
115            return Some(signer_config.clone());
116        }
117
118        // 回退:检查是否启用了本地 Signer 服务
119        if global_config.is_signer_enabled() && global_config.services.signer.is_some() {
120            // 自动生成指向本地 Signer 的客户端配置
121            // Signer gRPC 复用实例主 HTTP/HTTPS 端口
122            let http_cfg = global_config.bind.http.as_ref();
123            let port = http_cfg.map(|h| h.port).unwrap_or(8080);
124            let use_tls = http_cfg.is_some_and(|h| h.is_tls());
125            let protocol = if use_tls { "https" } else { "http" };
126            let tls_domain = if use_tls {
127                http_cfg.map(|h| h.domain_name.clone())
128            } else {
129                None
130            };
131
132            return Some(SignerClientConfig {
133                endpoint: format!("{protocol}://127.0.0.1:{port}"),
134                timeout_seconds: 30,
135                enable_tls: use_tls,
136                tls_domain,
137                ca_cert: None,
138                client_cert: None,
139                client_key: None,
140            });
141        }
142
143        None
144    }
145}